mostly done?
This commit is contained in:
parent
cbf35014cd
commit
18a40defba
28 changed files with 812 additions and 894 deletions
|
@ -9,21 +9,11 @@ import {
|
|||
selectCurrentPage,
|
||||
selectCurrentParams,
|
||||
} from "selectors/app";
|
||||
import {
|
||||
doSearch,
|
||||
} from 'actions/search'
|
||||
import {
|
||||
doFetchDaemonSettings
|
||||
} from 'actions/settings'
|
||||
import {
|
||||
doAuthenticate
|
||||
} from 'actions/user'
|
||||
import {
|
||||
doRewardList
|
||||
} from 'actions/rewards'
|
||||
import {
|
||||
doFileList
|
||||
} from 'actions/file_info'
|
||||
import { doSearch } from "actions/search";
|
||||
import { doFetchDaemonSettings } from "actions/settings";
|
||||
import { doAuthenticate } from "actions/user";
|
||||
import { doRewardList } from "actions/rewards";
|
||||
import { doFileList } from "actions/file_info";
|
||||
|
||||
const { remote, ipcRenderer, shell } = require("electron");
|
||||
const path = require("path");
|
||||
|
@ -231,14 +221,14 @@ export function doAlertError(errorList) {
|
|||
|
||||
export function doDaemonReady() {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(doAuthenticate());
|
||||
dispatch({
|
||||
type: types.DAEMON_READY
|
||||
})
|
||||
dispatch(doAuthenticate())
|
||||
dispatch(doChangePath('/discover'))
|
||||
dispatch(doFetchDaemonSettings())
|
||||
dispatch(doFileList())
|
||||
}
|
||||
type: types.DAEMON_READY,
|
||||
});
|
||||
dispatch(doChangePath("/discover"));
|
||||
dispatch(doFetchDaemonSettings());
|
||||
dispatch(doFileList());
|
||||
};
|
||||
}
|
||||
|
||||
export function doShowSnackBar(data) {
|
||||
|
|
|
@ -1,95 +1,110 @@
|
|||
import * as types from 'constants/action_types'
|
||||
import lbryio from 'lbryio'
|
||||
import {
|
||||
setLocal
|
||||
} from 'utils'
|
||||
import {
|
||||
doRewardList
|
||||
} from 'actions/rewards'
|
||||
import * as types from "constants/action_types";
|
||||
import lbryio from "lbryio";
|
||||
import { setLocal } from "utils";
|
||||
import { doRewardList } from "actions/rewards";
|
||||
import { selectEmailToVerify } from "selectors/user";
|
||||
|
||||
export function doAuthenticate() {
|
||||
return function(dispatch, getState) {
|
||||
dispatch({
|
||||
type: types.AUTHENTICATION_STARTED,
|
||||
})
|
||||
lbryio.authenticate().then((user) => {
|
||||
dispatch({
|
||||
type: types.AUTHENTICATION_SUCCESS,
|
||||
data: { user }
|
||||
})
|
||||
});
|
||||
lbryio
|
||||
.authenticate()
|
||||
.then(user => {
|
||||
dispatch({
|
||||
type: types.AUTHENTICATION_SUCCESS,
|
||||
data: { user },
|
||||
});
|
||||
|
||||
dispatch(doRewardList()) //FIXME - where should this happen?
|
||||
|
||||
}).catch((error) => {
|
||||
console.log('auth error')
|
||||
console.log(error)
|
||||
dispatch({
|
||||
type: types.AUTHENTICATION_FAILURE,
|
||||
data: { error }
|
||||
dispatch(doRewardList()); //FIXME - where should this happen?
|
||||
})
|
||||
})
|
||||
}
|
||||
.catch(error => {
|
||||
console.log("auth error");
|
||||
console.log(error);
|
||||
dispatch({
|
||||
type: types.AUTHENTICATION_FAILURE,
|
||||
data: { error },
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doUserEmailNew(email) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch({
|
||||
type: types.USER_EMAIL_NEW_STARTED,
|
||||
email: email
|
||||
})
|
||||
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 }
|
||||
})
|
||||
}
|
||||
email: email,
|
||||
});
|
||||
}
|
||||
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)
|
||||
setLocal("user_email_declined", true);
|
||||
dispatch({
|
||||
type: types.USER_EMAIL_DECLINE,
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doUserEmailVerify(email, verificationToken) {
|
||||
export function doUserEmailVerify(verificationToken) {
|
||||
return function(dispatch, getState) {
|
||||
const email = selectEmailToVerify(getState());
|
||||
|
||||
dispatch({
|
||||
type: types.USER_EMAIL_VERIFY_STARTED,
|
||||
code: code
|
||||
})
|
||||
code: verificationToken,
|
||||
});
|
||||
|
||||
const failure = (error) => {
|
||||
const failure = error => {
|
||||
dispatch({
|
||||
type: types.USER_EMAIL_VERIFY_FAILURE,
|
||||
data: { error: error.message }
|
||||
})
|
||||
}
|
||||
data: { error: error.message },
|
||||
});
|
||||
};
|
||||
|
||||
lbryio.call('user_email', 'confirm', {verification_token: verificationToken, email: email }, 'post').then((userEmail) => {
|
||||
if (userEmail.is_verified) {
|
||||
dispatch({
|
||||
type: types.USER_EMAIL_VERIFY_SUCCESS,
|
||||
data: { email }
|
||||
})
|
||||
} else {
|
||||
failure(new Error("Your email is still not verified.")) //shouldn't happen?
|
||||
}
|
||||
}, failure);
|
||||
}
|
||||
}
|
||||
lbryio
|
||||
.call(
|
||||
"user_email",
|
||||
"confirm",
|
||||
{ verification_token: verificationToken, email: email },
|
||||
"post"
|
||||
)
|
||||
.then(userEmail => {
|
||||
if (userEmail.is_verified) {
|
||||
dispatch({
|
||||
type: types.USER_EMAIL_VERIFY_SUCCESS,
|
||||
data: { email },
|
||||
});
|
||||
} else {
|
||||
failure(new Error("Your email is still not verified.")); //shouldn't happen?
|
||||
}
|
||||
}, failure);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import Header from "component/header";
|
|||
import ErrorModal from "component/errorModal";
|
||||
import DownloadingModal from "component/downloadingModal";
|
||||
import UpgradeModal from "component/upgradeModal";
|
||||
import WelcomeModal from "component/welcomeModal";
|
||||
import lbry from "lbry";
|
||||
import { Line } from "rc-progress";
|
||||
|
||||
|
@ -34,6 +35,7 @@ class App extends React.Component {
|
|||
{modal == "upgrade" && <UpgradeModal />}
|
||||
{modal == "downloading" && <DownloadingModal />}
|
||||
{modal == "error" && <ErrorModal />}
|
||||
{modal == "welcome" && <WelcomeModal />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,22 +1,16 @@
|
|||
import React from 'react'
|
||||
import {
|
||||
connect
|
||||
} from 'react-redux'
|
||||
import {
|
||||
doUserEmailDecline
|
||||
} from 'actions/user'
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
selectAuthenticationIsPending,
|
||||
selectEmailNewDeclined,
|
||||
selectEmailNewExistingEmail,
|
||||
selectUser,
|
||||
} from 'selectors/user'
|
||||
import Auth from './view'
|
||||
selectEmailToVerify,
|
||||
selectUserIsVerificationCandidate,
|
||||
} from "selectors/user";
|
||||
import Auth from "./view";
|
||||
|
||||
const select = (state) => ({
|
||||
const select = state => ({
|
||||
isPending: selectAuthenticationIsPending(state),
|
||||
existingEmail: selectEmailNewExistingEmail(state),
|
||||
user: selectUser(state),
|
||||
})
|
||||
email: selectEmailToVerify(state),
|
||||
isVerificationCandidate: selectUserIsVerificationCandidate(state),
|
||||
});
|
||||
|
||||
export default connect(select, null)(Auth)
|
||||
export default connect(select, null)(Auth);
|
||||
|
|
|
@ -1,29 +1,22 @@
|
|||
import React from 'react'
|
||||
import {BusyMessage} from 'component/common'
|
||||
import UserEmailNew from 'component/userEmailNew'
|
||||
import UserEmailVerify from 'component/userEmailVerify'
|
||||
import React from "react";
|
||||
import { BusyMessage } from "component/common";
|
||||
import UserEmailNew from "component/userEmailNew";
|
||||
import UserEmailVerify from "component/userEmailVerify";
|
||||
|
||||
export class Auth extends React.Component {
|
||||
render() {
|
||||
const {
|
||||
isPending,
|
||||
existingEmail,
|
||||
user,
|
||||
} = this.props
|
||||
|
||||
console.log('auth render')
|
||||
console.log(this.props)
|
||||
const { isPending, email, isVerificationCandidate } = this.props;
|
||||
|
||||
if (isPending) {
|
||||
return <BusyMessage message="Authenticating" />
|
||||
} else if (!existingEmail && !user.has_email) {
|
||||
return <UserEmailNew />
|
||||
} else if (!user.has_verified_email) {
|
||||
return <UserEmailVerify />
|
||||
return <BusyMessage message={__("Authenticating")} />;
|
||||
} else if (!email) {
|
||||
return <UserEmailNew />;
|
||||
} else if (isVerificationCandidate) {
|
||||
return <UserEmailVerify />;
|
||||
} else {
|
||||
return <span className="empty">Auth is done fix this yo</span>
|
||||
return <span className="empty">{__("No further steps.")}</span>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Auth
|
||||
export default Auth;
|
||||
|
|
|
@ -1,25 +1,22 @@
|
|||
import React from 'react'
|
||||
import {
|
||||
connect
|
||||
} from 'react-redux'
|
||||
import {
|
||||
doUserEmailDecline
|
||||
} from 'actions/user'
|
||||
import React from "react";
|
||||
import * as modal from "constants/modal_types";
|
||||
import { connect } from "react-redux";
|
||||
import { doUserEmailDecline } from "actions/user";
|
||||
import { doOpenModal } from "actions/app";
|
||||
import {
|
||||
selectAuthenticationIsPending,
|
||||
selectEmailNewDeclined,
|
||||
selectUser,
|
||||
} from 'selectors/user'
|
||||
import AuthOverlay from './view'
|
||||
selectUserIsAuthRequested,
|
||||
} from "selectors/user";
|
||||
import AuthOverlay from "./view";
|
||||
|
||||
const select = (state) => ({
|
||||
const select = state => ({
|
||||
isPending: selectAuthenticationIsPending(state),
|
||||
isEmailDeclined: selectEmailNewDeclined(state),
|
||||
user: selectUser(state),
|
||||
})
|
||||
isShowing: selectUserIsAuthRequested(state),
|
||||
});
|
||||
|
||||
const perform = (dispatch) => ({
|
||||
userEmailDecline: () => dispatch(doUserEmailDecline())
|
||||
})
|
||||
const perform = dispatch => ({
|
||||
userEmailDecline: () => dispatch(doUserEmailDecline()),
|
||||
openWelcomeModal: () => dispatch(doOpenModal(modal.WELCOME)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(AuthOverlay)
|
||||
export default connect(select, perform)(AuthOverlay);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from "react";
|
||||
import lbryio from "lbryio.js";
|
||||
import ModalPage from "component/modal-page.js";
|
||||
import {BusyMessage} from 'component/common'
|
||||
import Auth from 'component/auth'
|
||||
import Link from "component/link"
|
||||
import Auth from "component/auth";
|
||||
import Link from "component/link";
|
||||
|
||||
export class AuthOverlay extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -13,167 +13,68 @@ export class AuthOverlay extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.props.isShowing && !this.props.isPending && !nextProps.isShowing) {
|
||||
setTimeout(() => this.props.openWelcomeModal(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
onEmailSkipClick() {
|
||||
this.setState({ showNoEmailConfirm: true })
|
||||
this.setState({ showNoEmailConfirm: true });
|
||||
}
|
||||
|
||||
onEmailSkipConfirm() {
|
||||
this.props.userEmailDecline()
|
||||
this.props.userEmailDecline();
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
isPending,
|
||||
isEmailDeclined,
|
||||
user,
|
||||
} = this.props
|
||||
|
||||
if (!isEmailDeclined && (isPending || (user && !user.has_email))) {
|
||||
return <ModalPage className="modal-page--full" isOpen={true} contentLabel="Authentication">
|
||||
<h1>LBRY Early Access</h1>
|
||||
{ isPending ?
|
||||
<BusyMessage message="Preparing for early access" /> :
|
||||
<Auth /> }
|
||||
{ isPending ? '' :
|
||||
<div className="form-row-submit">
|
||||
{ this.state.showNoEmailConfirm ?
|
||||
<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>
|
||||
<Link className="button-text-help" onClick={ () => { this.onEmailSkipConfirm() }} label="Continue without email" />
|
||||
</div>
|
||||
:
|
||||
<Link className="button-text-help" onClick={ () => { this.onEmailSkipClick() }} label="Do I have to?" />
|
||||
}
|
||||
</div> }
|
||||
</ModalPage>
|
||||
if (!lbryio.enabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null
|
||||
const { isPending, isShowing } = this.props;
|
||||
|
||||
if (isShowing) {
|
||||
return (
|
||||
<ModalPage
|
||||
className="modal-page--full"
|
||||
isOpen={true}
|
||||
contentLabel="Authentication"
|
||||
>
|
||||
<h1>LBRY Early Access</h1>
|
||||
<Auth />
|
||||
{isPending
|
||||
? ""
|
||||
: <div className="form-row-submit">
|
||||
{this.state.showNoEmailConfirm
|
||||
? <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>
|
||||
<Link
|
||||
className="button-text-help"
|
||||
onClick={() => {
|
||||
this.onEmailSkipConfirm();
|
||||
}}
|
||||
label={__("Continue without email")}
|
||||
/>
|
||||
</div>
|
||||
: <Link
|
||||
className="button-text-help"
|
||||
onClick={() => {
|
||||
this.onEmailSkipClick();
|
||||
}}
|
||||
label={__("Do I have to?")}
|
||||
/>}
|
||||
</div>}
|
||||
</ModalPage>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default AuthOverlay
|
||||
|
||||
// class WelcomeStage extends React.Component {
|
||||
// static propTypes = {
|
||||
// endAuth: React.PropTypes.func,
|
||||
// }
|
||||
//
|
||||
// constructor(props) {
|
||||
// super(props);
|
||||
//
|
||||
// this.state = {
|
||||
// hasReward: false,
|
||||
// rewardAmount: null,
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// onRewardClaim(reward) {
|
||||
// this.setState({
|
||||
// hasReward: true,
|
||||
// rewardAmount: reward.amount
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// render() {
|
||||
// return (
|
||||
// !this.state.hasReward ?
|
||||
// <Modal type="custom" isOpen={true} contentLabel="Welcome to LBRY" {...this.props}>
|
||||
// <section>
|
||||
// <h3 className="modal__header">Welcome to LBRY.</h3>
|
||||
// <p>Using LBRY is like dating a centaur. Totally normal up top, and <em>way different</em> underneath.</p>
|
||||
// <p>Up top, LBRY is similar to popular media sites.</p>
|
||||
// <p>Below, LBRY is controlled by users -- you -- via blockchain and decentralization.</p>
|
||||
// <p>Thank you for making content freedom possible! Here's a nickel, kid.</p>
|
||||
// <div style={{textAlign: "center", marginBottom: "12px"}}>
|
||||
// <RewardLink type="new_user" button="primary" onRewardClaim={(event) => { this.onRewardClaim(event) }} onRewardFailure={() => this.props.setStage(null)} onConfirmed={() => { this.props.setStage(null) }} />
|
||||
// </div>
|
||||
// </section>
|
||||
// </Modal> :
|
||||
// <Modal type="alert" overlayClassName="modal-overlay modal-overlay--clear" isOpen={true} contentLabel="Welcome to LBRY" {...this.props} onConfirmed={() => { this.props.setStage(null) }}>
|
||||
// <section>
|
||||
// <h3 className="modal__header">About Your Reward</h3>
|
||||
// <p>You earned a reward of <CreditAmount amount={this.state.rewardAmount} label={false} /> LBRY credits, or <em>LBC</em>.</p>
|
||||
// <p>This reward will show in your Wallet momentarily, probably while you are reading this message.</p>
|
||||
// <p>LBC is used to compensate creators, to publish, and to have say in how the network works.</p>
|
||||
// <p>No need to understand it all just yet! Try watching or downloading something next.</p>
|
||||
// <p>Finally, know that LBRY is an early beta and that it earns the name.</p>
|
||||
// </section>
|
||||
// </Modal>
|
||||
// );
|
||||
// }
|
||||
// // }
|
||||
// //
|
||||
// // const ErrorStage = (props) => {
|
||||
// // return <section>
|
||||
// // <p>An error was encountered that we cannot continue from.</p>
|
||||
// // <p>At least we're earning the name beta.</p>
|
||||
// // { props.errorText ? <p>Message: {props.errorText}</p> : '' }
|
||||
// // <Link button="alt" label="Try Reload" onClick={() => { window.location.reload() } } />
|
||||
// // </section>
|
||||
// // }
|
||||
// // //
|
||||
// // // const PendingStage = (props) => {
|
||||
// // // return <section>
|
||||
// // // <BusyMessage message="Authenticating" />
|
||||
// // // </section>
|
||||
// // // }
|
||||
// // // //
|
||||
// // // //
|
||||
// // // // class CodeRequiredStage extends React.Component {
|
||||
// // // // constructor(props) {
|
||||
// // // // super(props);
|
||||
// // // //
|
||||
// // // // this._balanceSubscribeId = null
|
||||
// // // //
|
||||
// // // // this.state = {
|
||||
// // // // balance: 0,
|
||||
// // // // address: getLocal('wallet_address')
|
||||
// // // // };
|
||||
// // // // }
|
||||
// // // //
|
||||
// // // // componentWillMount() {
|
||||
// // // // this._balanceSubscribeId = lbry.balanceSubscribe((balance) => {
|
||||
// // // // this.setState({
|
||||
// // // // balance: balance
|
||||
// // // // });
|
||||
// // // // })
|
||||
// // // //
|
||||
// // // // if (!this.state.address) {
|
||||
// // // // lbry.wallet_unused_address().then((address) => {
|
||||
// // // // setLocal('wallet_address', address);
|
||||
// // // // this.setState({ address: address });
|
||||
// // // // });
|
||||
// // // // }
|
||||
// // // // }
|
||||
// // // //
|
||||
// // // // componentWillUnmount() {
|
||||
// // // // if (this._balanceSubscribeId) {
|
||||
// // // // lbry.balanceUnsubscribe(this._balanceSubscribeId)
|
||||
// // // // }
|
||||
// // // // }
|
||||
// // // //
|
||||
// // // // render() {
|
||||
// // // // const disabled = this.state.balance < 1;
|
||||
// // // // return (
|
||||
// // // // <div>
|
||||
// // // // <section className="section-spaced">
|
||||
// // // // <p>Early access to LBRY is restricted as we build and scale the network.</p>
|
||||
// // // // <p>There are two ways in.</p>
|
||||
// // // // <h3>Own LBRY Credits</h3>
|
||||
// // // // <p>If you own at least 1 LBC, you can get in right now.</p>
|
||||
// // // // <p style={{ textAlign: "center"}}><Link onClick={() => { setLocal('auth_bypassed', true); this.props.setStage(null); }}
|
||||
// // // // disabled={disabled} label="Let Me In" button={ disabled ? "alt" : "primary" } /></p>
|
||||
// // // // <p>Your balance is <CreditAmount amount={this.state.balance} />. To increase your balance, send credits to this address:</p>
|
||||
// // // // <p><Address address={ this.state.address ? this.state.address : "Generating Address..." } /></p>
|
||||
// // // // <p>If you don't understand how to send credits, then...</p>
|
||||
// // // // </section>
|
||||
// // // // <section>
|
||||
// // // // <h3>Wait For A Code</h3>
|
||||
// // // // <p>If you provide your email, you'll automatically receive a notification when the system is open.</p>
|
||||
// // // // <p><Link onClick={() => { this.props.setStage("email"); }} label="Return" /></p>
|
||||
// // // // </section>
|
||||
// // // // </div>
|
||||
// // // // );
|
||||
// // // // }
|
||||
// // // // }
|
||||
export default AuthOverlay;
|
||||
|
|
|
@ -1,41 +1,35 @@
|
|||
import React from 'react'
|
||||
import {
|
||||
connect,
|
||||
} from 'react-redux'
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
makeSelectHasClaimedReward,
|
||||
makeSelectClaimRewardError,
|
||||
makeSelectRewardByType,
|
||||
makeSelectIsRewardClaimPending,
|
||||
selectIsRewardEligible,
|
||||
} from 'selectors/rewards'
|
||||
import {
|
||||
doNavigate
|
||||
} from 'actions/app'
|
||||
import {
|
||||
doClaimReward,
|
||||
doClaimRewardClearError
|
||||
} from 'actions/rewards'
|
||||
import RewardLink from './view'
|
||||
} from "selectors/rewards";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doClaimReward, doClaimRewardClearError } from "actions/rewards";
|
||||
import RewardLink from "./view";
|
||||
|
||||
const makeSelect = () => {
|
||||
const selectHasClaimedReward = makeSelectHasClaimedReward()
|
||||
const selectIsPending = makeSelectIsRewardClaimPending()
|
||||
const selectError = makeSelectClaimRewardError()
|
||||
const selectHasClaimedReward = makeSelectHasClaimedReward();
|
||||
const selectIsPending = makeSelectIsRewardClaimPending();
|
||||
const selectReward = makeSelectRewardByType();
|
||||
const selectError = makeSelectClaimRewardError();
|
||||
|
||||
const select = (state, props) => ({
|
||||
isClaimed: selectHasClaimedReward(state, props),
|
||||
isEligible: selectIsRewardEligible(state),
|
||||
errorMessage: selectError(state, props),
|
||||
isPending: selectIsPending(state, props)
|
||||
})
|
||||
isPending: selectIsPending(state, props),
|
||||
reward: select,
|
||||
});
|
||||
|
||||
return select
|
||||
}
|
||||
return select;
|
||||
};
|
||||
|
||||
const perform = (dispatch) => ({
|
||||
claimReward: (reward) => dispatch(doClaimReward(reward)),
|
||||
clearError: (reward) => dispatch(doClaimRewardClearError(reward)),
|
||||
navigate: (path) => dispatch(doNavigate(path)),
|
||||
})
|
||||
const perform = dispatch => ({
|
||||
claimReward: reward => dispatch(doClaimReward(reward)),
|
||||
clearError: reward => dispatch(doClaimRewardClearError(reward)),
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
});
|
||||
|
||||
export default connect(makeSelect, perform)(RewardLink)
|
||||
export default connect(makeSelect, perform)(RewardLink);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react';
|
||||
import {Icon} from 'component/common';
|
||||
import Modal from 'component/modal';
|
||||
import Link from 'component/link'
|
||||
import React from "react";
|
||||
import { Icon } from "component/common";
|
||||
import Modal from "component/modal";
|
||||
import Link from "component/link";
|
||||
|
||||
const RewardLink = (props) => {
|
||||
const RewardLink = props => {
|
||||
const {
|
||||
reward,
|
||||
button,
|
||||
|
@ -11,22 +11,34 @@ const RewardLink = (props) => {
|
|||
clearError,
|
||||
errorMessage,
|
||||
isClaimed,
|
||||
isEligible,
|
||||
isPending
|
||||
} = props
|
||||
isPending,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div className="reward-link">
|
||||
{isClaimed
|
||||
? <span><Icon icon="icon-check" /> Reward claimed.</span>
|
||||
: <Link button={button ? button : 'alt'} disabled={isPending}
|
||||
label={ isPending ? "Claiming..." : "Claim Reward"} onClick={() => { claimReward(reward) }} />}
|
||||
{errorMessage ?
|
||||
<Modal isOpen={true} contentLabel="Reward Claim Error" className="error-modal" onConfirmed={() => { clearError(reward) }}>
|
||||
{errorMessage}
|
||||
</Modal>
|
||||
: ''}
|
||||
: <Link
|
||||
button={button ? button : "alt"}
|
||||
disabled={isPending}
|
||||
label={isPending ? "Claiming..." : "Claim Reward"}
|
||||
onClick={() => {
|
||||
claimReward(reward);
|
||||
}}
|
||||
/>}
|
||||
{errorMessage
|
||||
? <Modal
|
||||
isOpen={true}
|
||||
contentLabel="Reward Claim Error"
|
||||
className="error-modal"
|
||||
onConfirmed={() => {
|
||||
clearError(reward);
|
||||
}}
|
||||
>
|
||||
{errorMessage}
|
||||
</Modal>
|
||||
: ""}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default RewardLink
|
||||
);
|
||||
};
|
||||
export default RewardLink;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React from "react";
|
||||
import AuthPage from 'page/auth';
|
||||
import SettingsPage from "page/settings";
|
||||
import HelpPage from "page/help";
|
||||
import ReportPage from "page/report.js";
|
||||
|
@ -8,9 +7,8 @@ import WalletPage from "page/wallet";
|
|||
import ShowPage from "page/showPage";
|
||||
import PublishPage from "page/publish";
|
||||
import DiscoverPage from "page/discover";
|
||||
import SplashScreen from "component/splash.js";
|
||||
import DeveloperPage from "page/developer.js";
|
||||
import RewardsPage from "page/rewards.js";
|
||||
import RewardsPage from "page/rewards";
|
||||
import FileListDownloaded from "page/fileListDownloaded";
|
||||
import FileListPublished from "page/fileListPublished";
|
||||
import ChannelPage from "page/channel";
|
||||
|
@ -42,7 +40,6 @@ const Router = props => {
|
|||
discover: <DiscoverPage {...params} />,
|
||||
rewards: <RewardsPage {...params} />,
|
||||
search: <SearchPage {...params} />,
|
||||
"account-verification": <AuthPage {...params} />
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -1,25 +1,21 @@
|
|||
import React from 'react'
|
||||
import {
|
||||
connect
|
||||
} from 'react-redux'
|
||||
import {
|
||||
doUserEmailVerify
|
||||
} from 'actions/user'
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doUserEmailVerify } from "actions/user";
|
||||
import {
|
||||
selectEmailVerifyIsPending,
|
||||
selectEmailNewExistingEmail,
|
||||
selectEmailToVerify,
|
||||
selectEmailVerifyErrorMessage,
|
||||
} from 'selectors/user'
|
||||
import UserEmailVerify from './view'
|
||||
} from "selectors/user";
|
||||
import UserEmailVerify from "./view";
|
||||
|
||||
const select = (state) => ({
|
||||
const select = state => ({
|
||||
isPending: selectEmailVerifyIsPending(state),
|
||||
email: selectEmailNewExistingEmail,
|
||||
email: selectEmailToVerify,
|
||||
errorMessage: selectEmailVerifyErrorMessage(state),
|
||||
})
|
||||
});
|
||||
|
||||
const perform = (dispatch) => ({
|
||||
verifyUserEmail: (email, code) => dispatch(doUserEmailVerify(email, code))
|
||||
})
|
||||
const perform = dispatch => ({
|
||||
verifyUserEmail: code => dispatch(doUserEmailVerify(code)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(UserEmailVerify)
|
||||
export default connect(select, perform)(UserEmailVerify);
|
||||
|
|
22
ui/js/component/welcomeModal/index.jsx
Normal file
22
ui/js/component/welcomeModal/index.jsx
Normal file
|
@ -0,0 +1,22 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doCloseModal } from "actions/app";
|
||||
import { selectUserIsRewardApproved } from "selectors/user";
|
||||
import { makeSelectHasClaimedReward } from "selectors/rewards";
|
||||
import WelcomeModal from "./view";
|
||||
|
||||
const select = (state, props) => {
|
||||
const selectHasReward = makeSelectHasClaimedReward();
|
||||
|
||||
return {
|
||||
hasReward: selectHasReward(state, { reward_type: "new_user" }),
|
||||
isRewardApproved: selectUserIsRewardApproved(state),
|
||||
rewardAmount: 5,
|
||||
};
|
||||
};
|
||||
|
||||
const perform = dispatch => ({
|
||||
closeModal: () => dispatch(doCloseModal()),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(WelcomeModal);
|
79
ui/js/component/welcomeModal/view.jsx
Normal file
79
ui/js/component/welcomeModal/view.jsx
Normal file
|
@ -0,0 +1,79 @@
|
|||
import React from "react";
|
||||
import { Modal } from "component/modal";
|
||||
import { CreditAmount } from "component/common";
|
||||
import Link from "component/link";
|
||||
import RewardLink from "component/rewardLink";
|
||||
|
||||
class WelcomeModal extends React.Component {
|
||||
render() {
|
||||
const {
|
||||
closeModal,
|
||||
hasReward,
|
||||
isRewardApproved,
|
||||
rewardAmount,
|
||||
} = this.props;
|
||||
|
||||
return !hasReward
|
||||
? <Modal type="custom" isOpen={true} contentLabel="Welcome to LBRY">
|
||||
<section>
|
||||
<h3 className="modal__header">Welcome to LBRY.</h3>
|
||||
<p>
|
||||
Using LBRY is like dating a centaur. Totally normal up top, and
|
||||
{" "}<em>way different</em> underneath.
|
||||
</p>
|
||||
<p>Up top, LBRY is similar to popular media sites.</p>
|
||||
<p>
|
||||
Below, LBRY is controlled by users -- you -- via blockchain and
|
||||
decentralization.
|
||||
</p>
|
||||
<p>
|
||||
Thank you for making content freedom possible!
|
||||
{" "}{isRewardApproved ? __("Here's a nickel, kid.") : ""}
|
||||
</p>
|
||||
<div style={{ textAlign: "center", marginBottom: "12px" }}>
|
||||
{isRewardApproved
|
||||
? <RewardLink reward_type="new_user" button="primary" />
|
||||
: <Link
|
||||
button="primary"
|
||||
onClick={closeModal}
|
||||
label="Continue"
|
||||
/>}
|
||||
</div>
|
||||
</section>
|
||||
</Modal>
|
||||
: <Modal
|
||||
type="alert"
|
||||
overlayClassName="modal-overlay modal-overlay--clear"
|
||||
isOpen={true}
|
||||
contentLabel="Welcome to LBRY"
|
||||
onConfirmed={closeModal}
|
||||
>
|
||||
<section>
|
||||
<h3 className="modal__header">About Your Reward</h3>
|
||||
<p>
|
||||
You earned a reward of
|
||||
{" "}<CreditAmount amount={rewardAmount} label={false} /> LBRY
|
||||
credits, or <em>LBC</em>.
|
||||
</p>
|
||||
<p>
|
||||
This reward will show in your Wallet momentarily, probably while
|
||||
you are reading this message.
|
||||
</p>
|
||||
<p>
|
||||
LBC is used to compensate creators, to publish, and to have say in
|
||||
how the network works.
|
||||
</p>
|
||||
<p>
|
||||
No need to understand it all just yet! Try watching or downloading
|
||||
something next.
|
||||
</p>
|
||||
<p>
|
||||
Finally, know that LBRY is an early beta and that it earns the
|
||||
name.
|
||||
</p>
|
||||
</section>
|
||||
</Modal>;
|
||||
}
|
||||
}
|
||||
|
||||
export default WelcomeModal;
|
1
ui/js/constants/modal_types.js
Normal file
1
ui/js/constants/modal_types.js
Normal file
|
@ -0,0 +1 @@
|
|||
export const WELCOME = "welcome";
|
307
ui/js/lbryio.js
307
ui/js/lbryio.js
|
@ -1,134 +1,147 @@
|
|||
import { getSession, setSession, setLocal } from './utils.js';
|
||||
import lbry from './lbry.js';
|
||||
import { getSession, setSession, setLocal } from "./utils.js";
|
||||
import lbry from "./lbry.js";
|
||||
|
||||
const querystring = require('querystring');
|
||||
const querystring = require("querystring");
|
||||
|
||||
const lbryio = {
|
||||
_accessToken: getSession('accessToken'),
|
||||
_authenticationPromise: null,
|
||||
_user: null,
|
||||
enabled: true
|
||||
_accessToken: getSession("accessToken"),
|
||||
_authenticationPromise: null,
|
||||
_user: null,
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
const CONNECTION_STRING = process.env.LBRY_APP_API_URL
|
||||
? process.env.LBRY_APP_API_URL.replace(/\/*$/, '/') // exactly one slash at the end
|
||||
: 'https://api.lbry.io/';
|
||||
? process.env.LBRY_APP_API_URL.replace(/\/*$/, "/") // exactly one slash at the end
|
||||
: "https://api.lbry.io/";
|
||||
const EXCHANGE_RATE_TIMEOUT = 20 * 60 * 1000;
|
||||
|
||||
lbryio._exchangePromise = null;
|
||||
lbryio._exchangeLastFetched = null;
|
||||
lbryio.getExchangeRates = function() {
|
||||
if (
|
||||
!lbryio._exchangeLastFetched ||
|
||||
Date.now() - lbryio._exchangeLastFetched > EXCHANGE_RATE_TIMEOUT
|
||||
) {
|
||||
lbryio._exchangePromise = new Promise((resolve, reject) => {
|
||||
lbryio
|
||||
.call('lbc', 'exchange_rate', {}, 'get', true)
|
||||
.then(({ lbc_usd, lbc_btc, btc_usd }) => {
|
||||
const rates = { lbc_usd, lbc_btc, btc_usd };
|
||||
resolve(rates);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
lbryio._exchangeLastFetched = Date.now();
|
||||
}
|
||||
return lbryio._exchangePromise;
|
||||
if (
|
||||
!lbryio._exchangeLastFetched ||
|
||||
Date.now() - lbryio._exchangeLastFetched > EXCHANGE_RATE_TIMEOUT
|
||||
) {
|
||||
lbryio._exchangePromise = new Promise((resolve, reject) => {
|
||||
lbryio
|
||||
.call("lbc", "exchange_rate", {}, "get", true)
|
||||
.then(({ lbc_usd, lbc_btc, btc_usd }) => {
|
||||
const rates = { lbc_usd, lbc_btc, btc_usd };
|
||||
resolve(rates);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
lbryio._exchangeLastFetched = Date.now();
|
||||
}
|
||||
return lbryio._exchangePromise;
|
||||
};
|
||||
|
||||
lbryio.call = function(
|
||||
resource,
|
||||
action,
|
||||
params = {},
|
||||
method = 'get',
|
||||
evenIfDisabled = false
|
||||
resource,
|
||||
action,
|
||||
params = {},
|
||||
method = "get",
|
||||
evenIfDisabled = false
|
||||
) {
|
||||
// evenIfDisabled is just for development, when we may have some calls working and some not
|
||||
return new Promise((resolve, reject) => {
|
||||
if (
|
||||
!lbryio.enabled &&
|
||||
!evenIfDisabled &&
|
||||
(resource != 'discover' || action != 'list')
|
||||
) {
|
||||
console.log(__('Internal API disabled'));
|
||||
reject(new Error(__('LBRY internal API is disabled')));
|
||||
return;
|
||||
}
|
||||
// evenIfDisabled is just for development, when we may have some calls working and some not
|
||||
return new Promise((resolve, reject) => {
|
||||
if (
|
||||
!lbryio.enabled &&
|
||||
!evenIfDisabled &&
|
||||
(resource != "discover" || action != "list")
|
||||
) {
|
||||
console.log(__("Internal API disabled"));
|
||||
reject(new Error(__("LBRY internal API is disabled")));
|
||||
return;
|
||||
}
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.addEventListener('error', function(event) {
|
||||
reject(
|
||||
new Error(__('Something went wrong making an internal API call.'))
|
||||
);
|
||||
});
|
||||
xhr.addEventListener("error", function(event) {
|
||||
reject(
|
||||
new Error(__("Something went wrong making an internal API call."))
|
||||
);
|
||||
});
|
||||
|
||||
xhr.addEventListener('timeout', function() {
|
||||
reject(new Error(__('XMLHttpRequest connection timed out')));
|
||||
});
|
||||
xhr.addEventListener("timeout", function() {
|
||||
reject(new Error(__("XMLHttpRequest connection timed out")));
|
||||
});
|
||||
|
||||
xhr.addEventListener('load', function() {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
xhr.addEventListener("load", function() {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
|
||||
if (!response.success) {
|
||||
if (reject) {
|
||||
let error = new Error(response.error);
|
||||
error.xhr = xhr;
|
||||
reject(error);
|
||||
} else {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent('unhandledError', {
|
||||
detail: {
|
||||
connectionString: connectionString,
|
||||
method: action,
|
||||
params: params,
|
||||
message: response.error.message,
|
||||
...(response.error.data ? { data: response.error.data } : {})
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
resolve(response.data);
|
||||
}
|
||||
});
|
||||
if (!response.success) {
|
||||
if (reject) {
|
||||
let error = new Error(response.error);
|
||||
error.xhr = xhr;
|
||||
reject(error);
|
||||
} else {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("unhandledError", {
|
||||
detail: {
|
||||
connectionString: connectionString,
|
||||
method: action,
|
||||
params: params,
|
||||
message: response.error.message,
|
||||
...(response.error.data ? { data: response.error.data } : {}),
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
resolve(response.data);
|
||||
}
|
||||
});
|
||||
|
||||
// For social media auth:
|
||||
//const accessToken = localStorage.getItem('accessToken');
|
||||
//const fullParams = {...params, ... accessToken ? {access_token: accessToken} : {}};
|
||||
// For social media auth:
|
||||
//const accessToken = localStorage.getItem('accessToken');
|
||||
//const fullParams = {...params, ... accessToken ? {access_token: accessToken} : {}};
|
||||
|
||||
// Temp app ID based auth:
|
||||
const fullParams = { app_id: lbryio.getAccessToken(), ...params };
|
||||
// Temp app ID based auth:
|
||||
const fullParams = { app_id: lbryio.getAccessToken(), ...params };
|
||||
|
||||
if (method == 'get') {
|
||||
xhr.open(
|
||||
'get',
|
||||
CONNECTION_STRING +
|
||||
resource +
|
||||
'/' +
|
||||
action +
|
||||
'?' +
|
||||
querystring.stringify(fullParams),
|
||||
true
|
||||
);
|
||||
xhr.send();
|
||||
} else if (method == 'post') {
|
||||
xhr.open('post', CONNECTION_STRING + resource + '/' + action, true);
|
||||
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
xhr.send(querystring.stringify(fullParams));
|
||||
} else {
|
||||
reject(new Error(__('Invalid method')));
|
||||
}
|
||||
});
|
||||
if (method == "get") {
|
||||
xhr.open(
|
||||
"get",
|
||||
CONNECTION_STRING +
|
||||
resource +
|
||||
"/" +
|
||||
action +
|
||||
"?" +
|
||||
querystring.stringify(fullParams),
|
||||
true
|
||||
);
|
||||
xhr.send();
|
||||
} else if (method == "post") {
|
||||
xhr.open("post", CONNECTION_STRING + resource + "/" + action, true);
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
xhr.send(querystring.stringify(fullParams));
|
||||
} else {
|
||||
reject(new Error(__("Invalid method")));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
lbryio.getAccessToken = () => {
|
||||
const token = getSession('accessToken');
|
||||
return token ? token.toString().trim() : token;
|
||||
const token = getSession("accessToken");
|
||||
return token ? token.toString().trim() : token;
|
||||
};
|
||||
|
||||
lbryio.setAccessToken = token => {
|
||||
setSession('accessToken', token ? token.toString().trim() : token);
|
||||
setSession("accessToken", token ? token.toString().trim() : token);
|
||||
};
|
||||
|
||||
lbryio.setCurrentUser = (resolve, reject) => {
|
||||
lbryio
|
||||
.call("user", "me")
|
||||
.then(data => {
|
||||
lbryio.user = data;
|
||||
resolve(data);
|
||||
})
|
||||
.catch(function(err) {
|
||||
lbryio.setAccessToken(null);
|
||||
reject(err);
|
||||
});
|
||||
};
|
||||
|
||||
lbryio.authenticate = function() {
|
||||
|
@ -136,53 +149,57 @@ lbryio.authenticate = function() {
|
|||
return new Promise((resolve, reject) => {
|
||||
resolve({
|
||||
id: 1,
|
||||
has_verified_email: true
|
||||
})
|
||||
})
|
||||
language: "en",
|
||||
has_email: true,
|
||||
has_verified_email: true,
|
||||
is_reward_approved: false,
|
||||
is_reward_eligible: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
if (lbryio._authenticationPromise === null) {
|
||||
lbryio._authenticationPromise = new Promise((resolve, reject) => {
|
||||
lbry.status().then((response) => {
|
||||
lbry
|
||||
.status()
|
||||
.then(response => {
|
||||
let installation_id = response.installation_id;
|
||||
|
||||
let installation_id = response.installation_id.substring(0, response.installation_id.length - 2) + "E";
|
||||
|
||||
function setCurrentUser() {
|
||||
lbryio.call('user', 'me').then((data) => {
|
||||
lbryio.user = data
|
||||
resolve(data)
|
||||
}).catch(function(err) {
|
||||
lbryio.setAccessToken(null);
|
||||
reject(err);
|
||||
})
|
||||
}
|
||||
|
||||
if (!lbryio.getAccessToken()) {
|
||||
lbryio.call('user', 'new', {
|
||||
language: 'en',
|
||||
app_id: installation_id,
|
||||
}, 'post').then(function(responseData) {
|
||||
if (!responseData.id) {
|
||||
reject(new Error("Received invalid authentication response."));
|
||||
}
|
||||
lbryio.setAccessToken(installation_id)
|
||||
setLocal('auth_bypassed', false)
|
||||
setCurrentUser()
|
||||
}).catch(function(error) {
|
||||
/*
|
||||
until we have better error code format, assume all errors are duplicate application id
|
||||
if we're wrong, this will be caught by later attempts to make a valid call
|
||||
*/
|
||||
lbryio.setAccessToken(installation_id);
|
||||
setCurrentUser();
|
||||
});
|
||||
} else {
|
||||
setCurrentUser();
|
||||
}
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
return lbryio._authenticationPromise;
|
||||
if (!lbryio.getAccessToken()) {
|
||||
lbryio
|
||||
.call(
|
||||
"user",
|
||||
"new",
|
||||
{
|
||||
language: "en",
|
||||
app_id: installation_id,
|
||||
},
|
||||
"post"
|
||||
)
|
||||
.then(function(responseData) {
|
||||
if (!responseData.id) {
|
||||
reject(
|
||||
new Error("Received invalid authentication response.")
|
||||
);
|
||||
}
|
||||
lbryio.setAccessToken(installation_id);
|
||||
lbryio.setCurrentUser(resolve, reject);
|
||||
})
|
||||
.catch(function(error) {
|
||||
/*
|
||||
until we have better error code format, assume all errors are duplicate application id
|
||||
if we're wrong, this will be caught by later attempts to make a valid call
|
||||
*/
|
||||
lbryio.setAccessToken(installation_id);
|
||||
lbryio.setCurrentUser(resolve, reject);
|
||||
});
|
||||
} else {
|
||||
lbryio.setCurrentUser(resolve, reject);
|
||||
}
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
return lbryio._authenticationPromise;
|
||||
};
|
||||
|
||||
export default lbryio;
|
||||
|
|
127
ui/js/main.js
127
ui/js/main.js
|
@ -1,86 +1,85 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import lbry from './lbry.js';
|
||||
import lbryio from './lbryio.js';
|
||||
import App from 'component/app/index.js';
|
||||
import SnackBar from 'component/snackBar';
|
||||
import { Provider } from 'react-redux';
|
||||
import store from 'store.js';
|
||||
import SplashScreen from 'component/splash.js';
|
||||
import AuthOverlay from 'component/authOverlay';
|
||||
import { doChangePath, doNavigate, doDaemonReady } from 'actions/app';
|
||||
import { toQueryString } from 'util/query_params';
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import lbry from "./lbry.js";
|
||||
import App from "component/app/index.js";
|
||||
import SnackBar from "component/snackBar";
|
||||
import { Provider } from "react-redux";
|
||||
import store from "store.js";
|
||||
import SplashScreen from "component/splash.js";
|
||||
import AuthOverlay from "component/authOverlay";
|
||||
import { doChangePath, doNavigate, doDaemonReady } from "actions/app";
|
||||
import { toQueryString } from "util/query_params";
|
||||
|
||||
const { remote, ipcRenderer, shell } = require('electron');
|
||||
const contextMenu = remote.require('./menu/context-menu');
|
||||
const app = require('./app');
|
||||
const { remote, ipcRenderer, shell } = require("electron");
|
||||
const contextMenu = remote.require("./menu/context-menu");
|
||||
const app = require("./app");
|
||||
|
||||
lbry.showMenuIfNeeded();
|
||||
|
||||
window.addEventListener('contextmenu', event => {
|
||||
contextMenu.showContextMenu(
|
||||
remote.getCurrentWindow(),
|
||||
event.x,
|
||||
event.y,
|
||||
lbry.getClientSetting('showDeveloperMenu')
|
||||
);
|
||||
event.preventDefault();
|
||||
window.addEventListener("contextmenu", event => {
|
||||
contextMenu.showContextMenu(
|
||||
remote.getCurrentWindow(),
|
||||
event.x,
|
||||
event.y,
|
||||
lbry.getClientSetting("showDeveloperMenu")
|
||||
);
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
window.addEventListener('popstate', (event, param) => {
|
||||
const params = event.state;
|
||||
const pathParts = document.location.pathname.split('/');
|
||||
const route = '/' + pathParts[pathParts.length - 1];
|
||||
const queryString = toQueryString(params);
|
||||
window.addEventListener("popstate", (event, param) => {
|
||||
const params = event.state;
|
||||
const pathParts = document.location.pathname.split("/");
|
||||
const route = "/" + pathParts[pathParts.length - 1];
|
||||
const queryString = toQueryString(params);
|
||||
|
||||
let action;
|
||||
if (route.match(/html$/)) {
|
||||
action = doChangePath('/discover');
|
||||
} else {
|
||||
action = doChangePath(`${route}?${queryString}`);
|
||||
}
|
||||
let action;
|
||||
if (route.match(/html$/)) {
|
||||
action = doChangePath("/discover");
|
||||
} else {
|
||||
action = doChangePath(`${route}?${queryString}`);
|
||||
}
|
||||
|
||||
app.store.dispatch(action);
|
||||
app.store.dispatch(action);
|
||||
});
|
||||
|
||||
ipcRenderer.on('open-uri-requested', (event, uri) => {
|
||||
if (uri && uri.startsWith('lbry://')) {
|
||||
app.store.dispatch(doNavigate('/show', { uri }));
|
||||
}
|
||||
ipcRenderer.on("open-uri-requested", (event, uri) => {
|
||||
if (uri && uri.startsWith("lbry://")) {
|
||||
app.store.dispatch(doNavigate("/show", { uri }));
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('click', event => {
|
||||
var target = event.target;
|
||||
while (target && target !== document) {
|
||||
if (target.matches('a[href^="http"]')) {
|
||||
event.preventDefault();
|
||||
shell.openExternal(target.href);
|
||||
return;
|
||||
}
|
||||
target = target.parentNode;
|
||||
}
|
||||
document.addEventListener("click", event => {
|
||||
var target = event.target;
|
||||
while (target && target !== document) {
|
||||
if (target.matches('a[href^="http"]')) {
|
||||
event.preventDefault();
|
||||
shell.openExternal(target.href);
|
||||
return;
|
||||
}
|
||||
target = target.parentNode;
|
||||
}
|
||||
});
|
||||
|
||||
const initialState = app.store.getState();
|
||||
|
||||
var init = function() {
|
||||
function onDaemonReady() {
|
||||
window.sessionStorage.setItem('loaded', 'y'); //once we've made it here once per session, we don't need to show splash again
|
||||
app.store.dispatch(doDaemonReady())
|
||||
function onDaemonReady() {
|
||||
window.sessionStorage.setItem("loaded", "y"); //once we've made it here once per session, we don't need to show splash again
|
||||
app.store.dispatch(doDaemonReady());
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<div>{lbryio.enabled ? <AuthOverlay /> : ''}<App /><SnackBar /></div>
|
||||
</Provider>,
|
||||
canvas
|
||||
);
|
||||
}
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<div><AuthOverlay /><App /><SnackBar /></div>
|
||||
</Provider>,
|
||||
canvas
|
||||
);
|
||||
}
|
||||
|
||||
if (window.sessionStorage.getItem('loaded') == 'y') {
|
||||
onDaemonReady();
|
||||
} else {
|
||||
ReactDOM.render(<SplashScreen onLoadDone={onDaemonReady} />, canvas);
|
||||
}
|
||||
if (window.sessionStorage.getItem("loaded") == "y") {
|
||||
onDaemonReady();
|
||||
} else {
|
||||
ReactDOM.render(<SplashScreen onLoadDone={onDaemonReady} />, canvas);
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
import React from 'react'
|
||||
import {
|
||||
connect
|
||||
} from 'react-redux'
|
||||
import {
|
||||
doUserEmailDecline
|
||||
} from 'actions/user'
|
||||
import {
|
||||
selectAuthenticationIsPending,
|
||||
selectEmailNewDeclined,
|
||||
selectUser,
|
||||
} from 'selectors/user'
|
||||
import AuthPage from './view'
|
||||
|
||||
const select = (state) => ({
|
||||
isPending: selectAuthenticationIsPending(state),
|
||||
isEmailDeclined: selectEmailNewDeclined(state),
|
||||
user: selectUser(state),
|
||||
})
|
||||
|
||||
const perform = (dispatch) => ({
|
||||
userEmailDecline: () => dispatch(doUserEmailDecline())
|
||||
})
|
||||
|
||||
export default connect(select, perform)(AuthPage)
|
|
@ -1,19 +0,0 @@
|
|||
import React from 'react'
|
||||
import Auth from 'component/auth'
|
||||
|
||||
export class AuthPage extends React.Component {
|
||||
render() {
|
||||
return <main className="main--single-column">
|
||||
<section className="card">
|
||||
<div className="card__inner">
|
||||
<div className="card__title-identity"><h1>Early Access Verification</h1></div>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<Auth />
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
}
|
||||
}
|
||||
|
||||
export default AuthPage
|
|
@ -1,100 +0,0 @@
|
|||
import React from "react";
|
||||
import lbryio from "lbryio";
|
||||
import { CreditAmount, Icon } from "component/common.js";
|
||||
import SubHeader from "component/subHeader";
|
||||
import { RewardLink } from "component/reward-link";
|
||||
|
||||
export class RewardTile extends React.Component {
|
||||
static propTypes = {
|
||||
type: React.PropTypes.string.isRequired,
|
||||
title: React.PropTypes.string.isRequired,
|
||||
description: React.PropTypes.string.isRequired,
|
||||
claimed: React.PropTypes.bool.isRequired,
|
||||
value: React.PropTypes.number.isRequired,
|
||||
onRewardClaim: React.PropTypes.func,
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<section className="card">
|
||||
<div className="card__inner">
|
||||
<div className="card__title-primary">
|
||||
<CreditAmount amount={this.props.value} />
|
||||
<h3>{this.props.title}</h3>
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
{this.props.claimed
|
||||
? <span><Icon icon="icon-check" /> {__("Reward claimed.")}</span>
|
||||
: <RewardLink {...this.props} />}
|
||||
</div>
|
||||
<div className="card__content">{this.props.description}</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class RewardsPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
userRewards: null,
|
||||
failed: null,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.loadRewards();
|
||||
}
|
||||
|
||||
loadRewards() {
|
||||
lbryio.call("reward", "list", {}).then(
|
||||
userRewards => {
|
||||
this.setState({
|
||||
userRewards: userRewards,
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({ failed: true });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<main className="main--single-column">
|
||||
<SubHeader />
|
||||
<div>
|
||||
{!this.state.userRewards
|
||||
? this.state.failed
|
||||
? <div className="empty">{__("Failed to load rewards.")}</div>
|
||||
: ""
|
||||
: this.state.userRewards.map(
|
||||
({
|
||||
reward_type,
|
||||
reward_title,
|
||||
reward_description,
|
||||
transaction_id,
|
||||
reward_amount,
|
||||
}) => {
|
||||
return (
|
||||
<RewardTile
|
||||
key={reward_type}
|
||||
onRewardClaim={this.loadRewards}
|
||||
type={reward_type}
|
||||
title={__(reward_title)}
|
||||
description={__(reward_description)}
|
||||
claimed={!!transaction_id}
|
||||
value={reward_amount}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RewardsPage;
|
|
@ -1,28 +1,25 @@
|
|||
import React from 'react'
|
||||
import {
|
||||
connect,
|
||||
} from 'react-redux'
|
||||
import {
|
||||
doNavigate
|
||||
} from 'actions/app'
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "actions/app";
|
||||
import {
|
||||
selectFetchingRewards,
|
||||
selectIsRewardEligible,
|
||||
selectRewards,
|
||||
} from 'selectors/rewards'
|
||||
} from "selectors/rewards";
|
||||
import {
|
||||
selectUserIsRewardEligible
|
||||
} from 'selectors/user'
|
||||
import RewardsPage from './view'
|
||||
selectUserIsRewardEligible,
|
||||
selectUserHasEmail,
|
||||
selectUserIsRewardApproved,
|
||||
selectUserIsVerificationCandidate,
|
||||
} from "selectors/user";
|
||||
import RewardsPage from "./view";
|
||||
|
||||
const select = (state) => ({
|
||||
const select = state => ({
|
||||
fetching: selectFetchingRewards(state),
|
||||
rewards: selectRewards(state),
|
||||
isEligible: selectUserIsRewardEligible(state)
|
||||
})
|
||||
hasEmail: selectUserHasEmail(state),
|
||||
isEligible: selectUserIsRewardEligible(state),
|
||||
isVerificationCandidate: selectUserIsVerificationCandidate(state),
|
||||
});
|
||||
|
||||
const perform = (dispatch) => ({
|
||||
navigateToAuth: () => dispatch(doNavigate('/account-verification'))
|
||||
})
|
||||
|
||||
export default connect(select, perform)(RewardsPage)
|
||||
export default connect(select, null)(RewardsPage);
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import React from 'react';
|
||||
import lbryio from 'lbryio';
|
||||
import {BusyMessage, CreditAmount, Icon} from 'component/common';
|
||||
import SubHeader from 'component/subHeader'
|
||||
import Link from 'component/link'
|
||||
import RewardLink from 'component/rewardLink';
|
||||
import React from "react";
|
||||
import lbryio from "lbryio";
|
||||
import { BusyMessage, CreditAmount, Icon } from "component/common";
|
||||
import SubHeader from "component/subHeader";
|
||||
import Auth from "component/auth";
|
||||
import Link from "component/link";
|
||||
import RewardLink from "component/rewardLink";
|
||||
|
||||
const RewardTile = (props) => {
|
||||
const {
|
||||
reward,
|
||||
} = props
|
||||
const RewardTile = props => {
|
||||
const { reward } = props;
|
||||
|
||||
const claimed = !!reward.transaction_id
|
||||
const claimed = !!reward.transaction_id;
|
||||
|
||||
return (
|
||||
<section className="card">
|
||||
|
@ -22,43 +21,74 @@ const RewardTile = (props) => {
|
|||
<div className="card__actions">
|
||||
{claimed
|
||||
? <span><Icon icon="icon-check" /> Reward claimed.</span>
|
||||
: <RewardLink reward={reward} />}
|
||||
: <RewardLink reward_type={reward.reward_type} />}
|
||||
</div>
|
||||
<div className="card__content">{reward.reward_description}</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const RewardsPage = (props) => {
|
||||
const RewardsPage = props => {
|
||||
const {
|
||||
fetching,
|
||||
isEligible,
|
||||
navigateToAuth,
|
||||
isVerificationCandidate,
|
||||
hasEmail,
|
||||
rewards,
|
||||
} = props
|
||||
} = props;
|
||||
|
||||
let content
|
||||
console.log(props);
|
||||
|
||||
if (!isEligible) {
|
||||
content = <div className="empty">
|
||||
You are not eligible to claim rewards. { ' ' }
|
||||
<Link onClick={navigateToAuth} label="Become eligible" />.
|
||||
</div>
|
||||
let content,
|
||||
isCard = false;
|
||||
|
||||
if (!hasEmail || isVerificationCandidate) {
|
||||
content = (
|
||||
<div>
|
||||
<p>
|
||||
{__(
|
||||
"Additional information is required to be eligible for the rewards program."
|
||||
)}
|
||||
</p>
|
||||
<Auth />
|
||||
</div>
|
||||
);
|
||||
isCard = true;
|
||||
} else if (!isEligible) {
|
||||
isCard = true;
|
||||
content = (
|
||||
<div className="empty">
|
||||
<p>{__("You are not eligible to claim rewards.")}</p>
|
||||
<p>
|
||||
To become eligible, email
|
||||
{" "}<Link href="mailto:help@lbry.io" label="help@lbry.io" /> with a
|
||||
link to a public social media profile.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
} else if (fetching) {
|
||||
content = <BusyMessage message="Fetching rewards" />
|
||||
content = <BusyMessage message="Fetching rewards" />;
|
||||
} else if (rewards.length > 0) {
|
||||
content = rewards.map(reward => <RewardTile key={reward.reward_type} reward={reward} />)
|
||||
content = rewards.map(reward =>
|
||||
<RewardTile key={reward.reward_type} reward={reward} />
|
||||
);
|
||||
} else {
|
||||
content = <div className="empty">Failed to load rewards.</div>
|
||||
content = <div className="empty">{__("Failed to load rewards.")}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="main--single-column">
|
||||
<SubHeader />
|
||||
{content}
|
||||
{isCard
|
||||
? <section className="card">
|
||||
<div className="card__content">
|
||||
{content}
|
||||
</div>
|
||||
</section>
|
||||
: content}
|
||||
</main>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default RewardsPage;
|
||||
|
|
|
@ -229,25 +229,32 @@ class SettingsPage extends React.Component {
|
|||
</div>
|
||||
</section>
|
||||
|
||||
{/*}
|
||||
<section className="card">
|
||||
<div className="card__content">
|
||||
<h3>{__("Language")}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<div className="form-row">
|
||||
<FormField type="radio"
|
||||
name="language"
|
||||
label={__("English")}
|
||||
onChange={() => { this.onLanguageChange('en') }}
|
||||
defaultChecked={this.state.language=='en'} />
|
||||
<FormField
|
||||
type="radio"
|
||||
name="language"
|
||||
label={__("English")}
|
||||
onChange={() => {
|
||||
this.onLanguageChange("en");
|
||||
}}
|
||||
defaultChecked={this.state.language == "en"}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<FormField type="radio"
|
||||
name="language"
|
||||
label="Serbian"
|
||||
onChange={() => { this.onLanguageChange('rs') }}
|
||||
defaultChecked={this.state.language=='rs'} />
|
||||
<FormField
|
||||
type="radio"
|
||||
name="language"
|
||||
label="Serbian"
|
||||
onChange={() => {
|
||||
this.onLanguageChange("rs");
|
||||
}}
|
||||
defaultChecked={this.state.language == "rs"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>*/}
|
||||
|
|
|
@ -1,91 +1,98 @@
|
|||
import * as types from 'constants/action_types'
|
||||
import {
|
||||
getLocal
|
||||
} from 'utils'
|
||||
import * as types from "constants/action_types";
|
||||
import { getLocal } from "utils";
|
||||
|
||||
const reducers = {}
|
||||
const reducers = {};
|
||||
|
||||
const defaultState = {
|
||||
authenticationIsPending: false,
|
||||
emailNewIsPending: false,
|
||||
emailNewErrorMessage: '',
|
||||
emailNewDeclined: getLocal('user_email_declined', false),
|
||||
user: undefined
|
||||
}
|
||||
emailNewErrorMessage: "",
|
||||
emailNewDeclined: getLocal("user_email_declined", false),
|
||||
emailToVerify: "",
|
||||
user: undefined,
|
||||
};
|
||||
|
||||
reducers[types.AUTHENTICATION_STARTED] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
authenticationIsPending: true
|
||||
})
|
||||
}
|
||||
authenticationIsPending: true,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.AUTHENTICATION_SUCCESS] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
authenticationIsPending: false,
|
||||
user: action.data.user,
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.AUTHENTICATION_FAILURE] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
authenticationIsPending: false,
|
||||
user: null,
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.USER_EMAIL_DECLINE] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
emailNewDeclined: true
|
||||
})
|
||||
}
|
||||
emailNewDeclined: true,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.USER_EMAIL_NEW_STARTED] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
emailNewIsPending: true,
|
||||
emailNewErrorMessage: ''
|
||||
})
|
||||
}
|
||||
emailNewErrorMessage: "",
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.USER_EMAIL_NEW_SUCCESS] = function(state, action) {
|
||||
let user = Object.assign({}, state.user);
|
||||
user.has_email = true;
|
||||
return Object.assign({}, state, {
|
||||
emailToVerify: action.data.email,
|
||||
emailNewIsPending: false,
|
||||
})
|
||||
}
|
||||
user: user,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.USER_EMAIL_NEW_EXISTS] = function(state, action) {
|
||||
let user = Object.assign({}, state.user);
|
||||
return Object.assign({}, state, {
|
||||
emailNewExistingEmail: action.data.email,
|
||||
emailToVerify: action.data.email,
|
||||
emailNewIsPending: false,
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.USER_EMAIL_NEW_FAILURE] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
emailNewIsPending: false,
|
||||
emailNewErrorMessage: action.data.error
|
||||
})
|
||||
}
|
||||
emailNewErrorMessage: action.data.error,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.USER_EMAIL_VERIFY_STARTED] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
emailVerifyIsPending: true,
|
||||
emailVerifyErrorMessage: ''
|
||||
})
|
||||
}
|
||||
emailVerifyErrorMessage: "",
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.USER_EMAIL_VERIFY_SUCCESS] = function(state, action) {
|
||||
let user = Object.assign({}, state.user);
|
||||
user.has_email = true;
|
||||
return Object.assign({}, state, {
|
||||
emailToVerify: "",
|
||||
emailVerifyIsPending: false,
|
||||
})
|
||||
}
|
||||
user: user,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.USER_EMAIL_VERIFY_FAILURE] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
emailVerifyIsPending: false,
|
||||
emailVerifyErrorMessage: action.data.error
|
||||
})
|
||||
}
|
||||
|
||||
emailVerifyErrorMessage: action.data.error,
|
||||
});
|
||||
};
|
||||
|
||||
export default function reducer(state = defaultState, action) {
|
||||
const handler = reducers[action.type];
|
||||
|
|
|
@ -54,8 +54,6 @@ export const selectPageTitle = createSelector(
|
|||
return __("Publishes");
|
||||
case "discover":
|
||||
return __("Home");
|
||||
case 'account-verification':
|
||||
return __('Early Access Verification')
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -5,88 +5,75 @@ const _selectState = state => state.rewards || {};
|
|||
|
||||
export const selectRewardsByType = createSelector(
|
||||
_selectState,
|
||||
(state) => state.byRewardType || {}
|
||||
)
|
||||
state => state.byRewardType || {}
|
||||
);
|
||||
|
||||
export const selectRewards = createSelector(
|
||||
selectRewardsByType,
|
||||
(byType) => Object.values(byType) || []
|
||||
)
|
||||
byType => Object.values(byType) || []
|
||||
);
|
||||
|
||||
export const selectIsRewardEligible = createSelector(
|
||||
selectUser,
|
||||
(user) => user.can_claim_rewards
|
||||
)
|
||||
user => user.can_claim_rewards
|
||||
);
|
||||
|
||||
export const selectClaimedRewards = createSelector(
|
||||
selectRewards,
|
||||
(rewards) => rewards.filter(reward => reward.transaction_id !== "")
|
||||
)
|
||||
export const selectClaimedRewards = createSelector(selectRewards, rewards =>
|
||||
rewards.filter(reward => reward.transaction_id !== "")
|
||||
);
|
||||
|
||||
export const selectClaimedRewardsByType = createSelector(
|
||||
selectClaimedRewards,
|
||||
(claimedRewards) => {
|
||||
const byType = {}
|
||||
claimedRewards.forEach(reward => byType[reward.reward_type] = reward)
|
||||
return byType
|
||||
claimedRewards => {
|
||||
const byType = {};
|
||||
claimedRewards.forEach(reward => (byType[reward.reward_type] = reward));
|
||||
return byType;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
export const selectFetchingRewards = createSelector(
|
||||
_selectState,
|
||||
(state) => !!state.fetching
|
||||
)
|
||||
state => !!state.fetching
|
||||
);
|
||||
|
||||
export const selectHasClaimedReward = (state, props) => {
|
||||
return !!selectClaimedRewardsByType[props.reward.reward_type]
|
||||
}
|
||||
return !!selectClaimedRewardsByType[props.reward_type];
|
||||
};
|
||||
|
||||
export const makeSelectHasClaimedReward = () => {
|
||||
return createSelector(
|
||||
selectHasClaimedReward,
|
||||
(claimed) => claimed
|
||||
)
|
||||
}
|
||||
return createSelector(selectHasClaimedReward, claimed => claimed);
|
||||
};
|
||||
|
||||
export const selectClaimsPendingByType = createSelector(
|
||||
_selectState,
|
||||
(state) => state.claimPendingByType
|
||||
)
|
||||
state => state.claimPendingByType
|
||||
);
|
||||
|
||||
const selectIsClaimRewardPending = (state, props) => {
|
||||
return selectClaimsPendingByType(state, props)[props.reward.reward_type]
|
||||
}
|
||||
return selectClaimsPendingByType(state, props)[props.reward_type];
|
||||
};
|
||||
|
||||
export const makeSelectIsRewardClaimPending = () => {
|
||||
return createSelector(
|
||||
selectIsClaimRewardPending,
|
||||
(isClaiming) => isClaiming
|
||||
)
|
||||
}
|
||||
return createSelector(selectIsClaimRewardPending, isClaiming => isClaiming);
|
||||
};
|
||||
|
||||
export const selectClaimErrorsByType = createSelector(
|
||||
_selectState,
|
||||
(state) => state.claimErrorsByType
|
||||
)
|
||||
state => state.claimErrorsByType
|
||||
);
|
||||
|
||||
const selectClaimRewardError = (state, props) => {
|
||||
return selectClaimErrorsByType(state, props)[props.reward.reward_type]
|
||||
}
|
||||
return selectClaimErrorsByType(state, props)[props.reward_type];
|
||||
};
|
||||
|
||||
export const makeSelectClaimRewardError = () => {
|
||||
return createSelector(
|
||||
selectClaimRewardError,
|
||||
(errorMessage) => errorMessage
|
||||
)
|
||||
}
|
||||
return createSelector(selectClaimRewardError, errorMessage => errorMessage);
|
||||
};
|
||||
|
||||
const selectRewardByType = (state, props) => {
|
||||
return selectRewardsByType(state)[props.reward_type]
|
||||
}
|
||||
return selectRewardsByType(state)[props.reward_type];
|
||||
};
|
||||
|
||||
export const makeSelectRewardByType = () => {
|
||||
return createSelector(
|
||||
selectRewardByType,
|
||||
(reward) => reward
|
||||
)
|
||||
}
|
||||
return createSelector(selectRewardByType, reward => reward);
|
||||
};
|
||||
|
|
|
@ -68,7 +68,5 @@ export const selectWunderBarIcon = createSelector(selectCurrentPage, page => {
|
|||
return "icon-code";
|
||||
case "discover":
|
||||
return "icon-home";
|
||||
case 'account-verification':
|
||||
return 'icon-lock'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,48 +1,77 @@
|
|||
import { createSelector } from 'reselect'
|
||||
import { createSelector } from "reselect";
|
||||
|
||||
export const _selectState = state => state.user || {}
|
||||
export const _selectState = state => state.user || {};
|
||||
|
||||
export const selectAuthenticationIsPending = createSelector(
|
||||
_selectState,
|
||||
(state) => state.authenticationIsPending
|
||||
)
|
||||
state => state.authenticationIsPending
|
||||
);
|
||||
|
||||
export const selectUser = createSelector(
|
||||
_selectState,
|
||||
(state) => state.user
|
||||
)
|
||||
state => state.user || {}
|
||||
);
|
||||
|
||||
export const selectEmailToVerify = createSelector(
|
||||
_selectState,
|
||||
state => state.emailToVerify
|
||||
);
|
||||
|
||||
export const selectUserHasEmail = createSelector(
|
||||
selectUser,
|
||||
selectEmailToVerify,
|
||||
(user, email) => user.has_email || email
|
||||
);
|
||||
|
||||
export const selectUserIsRewardEligible = createSelector(
|
||||
_selectState,
|
||||
(state) => state.user.can_claim_rewards
|
||||
)
|
||||
selectUser,
|
||||
user => user.is_reward_eligible
|
||||
);
|
||||
|
||||
export const selectUserIsRewardApproved = createSelector(
|
||||
selectUser,
|
||||
user => user.is_reward_approved
|
||||
);
|
||||
|
||||
export const selectEmailNewIsPending = createSelector(
|
||||
_selectState,
|
||||
(state) => state.emailNewIsPending
|
||||
)
|
||||
state => state.emailNewIsPending
|
||||
);
|
||||
|
||||
export const selectEmailNewErrorMessage = createSelector(
|
||||
_selectState,
|
||||
(state) => state.emailNewErrorMessage
|
||||
)
|
||||
state => state.emailNewErrorMessage
|
||||
);
|
||||
|
||||
export const selectEmailNewDeclined = createSelector(
|
||||
_selectState,
|
||||
(state) => state.emailNewDeclined
|
||||
)
|
||||
|
||||
export const selectEmailNewExistingEmail = createSelector(
|
||||
_selectState,
|
||||
(state) => state.emailNewExistingEmail
|
||||
)
|
||||
state => state.emailNewDeclined
|
||||
);
|
||||
|
||||
export const selectEmailVerifyIsPending = createSelector(
|
||||
_selectState,
|
||||
(state) => state.emailVerifyIsPending
|
||||
)
|
||||
state => state.emailVerifyIsPending
|
||||
);
|
||||
|
||||
export const selectEmailVerifyErrorMessage = createSelector(
|
||||
_selectState,
|
||||
(state) => state.emailVerifyErrorMessage
|
||||
)
|
||||
state => state.emailVerifyErrorMessage
|
||||
);
|
||||
|
||||
export const selectUserIsVerificationCandidate = createSelector(
|
||||
selectUserIsRewardEligible,
|
||||
selectUserIsRewardApproved,
|
||||
selectEmailToVerify,
|
||||
selectUser,
|
||||
(isEligible, isApproved, emailToVerify, user) =>
|
||||
(isEligible && !isApproved) || (emailToVerify && !user.has_email)
|
||||
);
|
||||
|
||||
export const selectUserIsAuthRequested = createSelector(
|
||||
selectEmailNewDeclined,
|
||||
selectAuthenticationIsPending,
|
||||
selectUserIsVerificationCandidate,
|
||||
selectUserHasEmail,
|
||||
(isEmailDeclined, isPending, isVerificationCandidate, hasEmail) =>
|
||||
!isEmailDeclined && (isPending || !hasEmail || isVerificationCandidate)
|
||||
);
|
||||
|
|
|
@ -25,7 +25,7 @@ $padding-card-horizontal: $spacing-vertical * 2/3;
|
|||
}
|
||||
.card__title-primary {
|
||||
padding: 0 $padding-card-horizontal;
|
||||
margin-top: $spacing-vertical;
|
||||
margin-top: $spacing-vertical * 2/3;
|
||||
}
|
||||
.card__title-identity {
|
||||
padding: 0 $padding-card-horizontal;
|
||||
|
|
Loading…
Add table
Reference in a new issue