moderate progress
This commit is contained in:
parent
b3de4ceee9
commit
16abedbf3a
21 changed files with 228 additions and 78 deletions
|
@ -8,13 +8,11 @@ import {
|
|||
selectPageTitle,
|
||||
selectCurrentPage,
|
||||
selectCurrentParams,
|
||||
selectWelcomeModalAcknowledged,
|
||||
} from "selectors/app";
|
||||
import { doSearch } from "actions/search";
|
||||
import { doFetchDaemonSettings } from "actions/settings";
|
||||
import { doAuthenticate } from "actions/user";
|
||||
import { doFileList } from "actions/file_info";
|
||||
import * as modals from "constants/modal_types";
|
||||
|
||||
const { remote, ipcRenderer, shell } = require("electron");
|
||||
const path = require("path");
|
||||
|
@ -220,17 +218,13 @@ export function doAlertError(errorList) {
|
|||
}
|
||||
|
||||
export function doDaemonReady() {
|
||||
return function(dispatch, getState) {
|
||||
const showWelcome = !selectWelcomeModalAcknowledged(getState());
|
||||
return function(dispatch) {
|
||||
dispatch(doAuthenticate());
|
||||
dispatch({
|
||||
type: types.DAEMON_READY,
|
||||
});
|
||||
dispatch(doFetchDaemonSettings());
|
||||
dispatch(doFileList());
|
||||
if (showWelcome) {
|
||||
dispatch(doOpenModal(modals.WELCOME));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,40 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { selectCurrentModal } from "selectors/app";
|
||||
import { doCheckUpgradeAvailable, doAlertError } from "actions/app";
|
||||
import {
|
||||
doCheckUpgradeAvailable,
|
||||
doOpenModal,
|
||||
doAlertError,
|
||||
} from "actions/app";
|
||||
import { doUpdateBalance } from "actions/wallet";
|
||||
import { selectWelcomeModalAcknowledged } from "selectors/app";
|
||||
import rewards from "rewards";
|
||||
import {
|
||||
selectFetchingRewards,
|
||||
makeSelectHasClaimedReward,
|
||||
} from "selectors/rewards";
|
||||
import { selectUser } from "selectors/user";
|
||||
import App from "./view";
|
||||
import * as modals from "constants/modal_types";
|
||||
|
||||
const select = state => ({
|
||||
modal: selectCurrentModal(state),
|
||||
});
|
||||
const select = (state, props) => {
|
||||
const selectHasClaimed = makeSelectHasClaimedReward();
|
||||
|
||||
return {
|
||||
modal: selectCurrentModal(state),
|
||||
isWelcomeAcknowledged: selectWelcomeModalAcknowledged(state),
|
||||
isFetchingRewards: selectFetchingRewards(state),
|
||||
isWelcomeRewardClaimed: selectHasClaimed(state, {
|
||||
reward_type: rewards.TYPE_NEW_USER,
|
||||
}),
|
||||
user: selectUser(state),
|
||||
};
|
||||
};
|
||||
|
||||
const perform = dispatch => ({
|
||||
alertError: errorList => dispatch(doAlertError(errorList)),
|
||||
checkUpgradeAvailable: () => dispatch(doCheckUpgradeAvailable()),
|
||||
openWelcomeModal: () => dispatch(doOpenModal(modals.WELCOME)),
|
||||
updateBalance: balance => dispatch(doUpdateBalance(balance)),
|
||||
});
|
||||
|
||||
|
|
|
@ -11,17 +11,43 @@ import * as modals from "constants/modal_types";
|
|||
|
||||
class App extends React.PureComponent {
|
||||
componentWillMount() {
|
||||
const { alertError, checkUpgradeAvailable, updateBalance } = this.props;
|
||||
|
||||
document.addEventListener("unhandledError", event => {
|
||||
this.props.alertError(event.detail);
|
||||
alertError(event.detail);
|
||||
});
|
||||
|
||||
if (!this.props.upgradeSkipped) {
|
||||
this.props.checkUpgradeAvailable();
|
||||
checkUpgradeAvailable();
|
||||
}
|
||||
|
||||
lbry.balanceSubscribe(balance => {
|
||||
this.props.updateBalance(balance);
|
||||
updateBalance(balance);
|
||||
});
|
||||
|
||||
this.showWelcome(this.props);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.showWelcome(nextProps);
|
||||
}
|
||||
|
||||
showWelcome(props) {
|
||||
const {
|
||||
isFetchingRewards,
|
||||
isWelcomeAcknowledged,
|
||||
isWelcomeRewardClaimed,
|
||||
openWelcomeModal,
|
||||
user,
|
||||
} = props;
|
||||
|
||||
if (
|
||||
!isWelcomeAcknowledged &&
|
||||
user &&
|
||||
(!isFetchingRewards || !isWelcomeRewardClaimed)
|
||||
) {
|
||||
openWelcomeModal();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -4,12 +4,14 @@ import {
|
|||
selectAuthenticationIsPending,
|
||||
selectEmailToVerify,
|
||||
selectUserIsVerificationCandidate,
|
||||
selectUser,
|
||||
} from "selectors/user";
|
||||
import Auth from "./view";
|
||||
|
||||
const select = state => ({
|
||||
isPending: selectAuthenticationIsPending(state),
|
||||
email: selectEmailToVerify(state),
|
||||
user: selectUser(state),
|
||||
isVerificationCandidate: selectUserIsVerificationCandidate(state),
|
||||
});
|
||||
|
||||
|
|
|
@ -2,17 +2,20 @@ import React from "react";
|
|||
import { BusyMessage } from "component/common";
|
||||
import UserEmailNew from "component/userEmailNew";
|
||||
import UserEmailVerify from "component/userEmailVerify";
|
||||
import UserVerify from "component/userVerify";
|
||||
|
||||
export class Auth extends React.PureComponent {
|
||||
render() {
|
||||
const { isPending, email, isVerificationCandidate } = this.props;
|
||||
const { email, isPending, isVerificationCandidate, user } = this.props;
|
||||
|
||||
if (isPending) {
|
||||
return <BusyMessage message={__("Authenticating")} />;
|
||||
} else if (!email) {
|
||||
} else if (user && !user.has_verified_email && !email) {
|
||||
return <UserEmailNew />;
|
||||
} else if (isVerificationCandidate) {
|
||||
} else if (user && !user.has_verified_email) {
|
||||
return <UserEmailVerify />;
|
||||
} else if (user && !user.is_identity_verified) {
|
||||
return <UserVerify />;
|
||||
} else {
|
||||
return <span className="empty">{__("No further steps.")}</span>;
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ export class AuthOverlay extends React.PureComponent {
|
|||
? ""
|
||||
: <div className="form-row-submit">
|
||||
{!hasEmail && this.state.showNoEmailConfirm
|
||||
? <div className="help form-input-width">
|
||||
? <div>
|
||||
<p>
|
||||
{__(
|
||||
"If you continue without an email, you will be ineligible to earn free LBC rewards, as well as unable to receive security related communications."
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from "react";
|
||||
import { formatCredits } from "utils";
|
||||
import lbry from "../lbry.js";
|
||||
|
||||
//component/icon.js
|
||||
|
@ -78,7 +79,7 @@ export class CreditAmount extends React.PureComponent {
|
|||
};
|
||||
|
||||
render() {
|
||||
const formattedAmount = lbry.formatCredits(
|
||||
const formattedAmount = formatCredits(
|
||||
this.props.amount,
|
||||
this.props.precision
|
||||
);
|
||||
|
@ -140,7 +141,7 @@ export class Address extends React.PureComponent {
|
|||
}}
|
||||
style={addressStyle}
|
||||
readOnly="readonly"
|
||||
value={this.props.address}
|
||||
value={this.props.address || ""}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import React from "react";
|
||||
import lbry from "lbry";
|
||||
import { formatCredits } from "utils";
|
||||
import { connect } from "react-redux";
|
||||
import { selectBalance } from "selectors/wallet";
|
||||
import { doNavigate, doHistoryBack } from "actions/app";
|
||||
import Header from "./view";
|
||||
|
||||
const select = state => ({
|
||||
balance: lbry.formatCredits(selectBalance(state), 1),
|
||||
balance: formatCredits(selectBalance(state), 1),
|
||||
publish: __("Publish"),
|
||||
});
|
||||
|
||||
|
|
|
@ -31,8 +31,11 @@ class ModalWelcome extends React.PureComponent {
|
|||
)}
|
||||
</p>
|
||||
<p>
|
||||
{__("Thank you for making content freedom possible!")}
|
||||
{" "}{isRewardApproved ? __("Here's a nickel, kid.") : ""}
|
||||
{__("Please have")} {" "}
|
||||
{reward &&
|
||||
<CreditAmount amount={parseFloat(reward.reward_amount)} />}
|
||||
{!reward && <span className="credit-amount">{__("??")}</span>}
|
||||
{" "} {__("as a thank you for building content freedom.")}
|
||||
</p>
|
||||
<div className="text-center">
|
||||
{isRewardApproved &&
|
||||
|
@ -40,15 +43,11 @@ class ModalWelcome extends React.PureComponent {
|
|||
{!isRewardApproved &&
|
||||
<Link
|
||||
button="primary"
|
||||
onClick={closeModal}
|
||||
label={__("Continue")}
|
||||
onClick={verifyAccount}
|
||||
label={__("Get Welcome Credits")}
|
||||
/>}
|
||||
{!isRewardApproved &&
|
||||
<Link
|
||||
button="alt"
|
||||
onClick={verifyAccount}
|
||||
label={__("Do Account Thing")}
|
||||
/>}
|
||||
<Link button="alt" onClick={closeModal} label={__("Skip")} />}
|
||||
</div>
|
||||
</section>
|
||||
</Modal>
|
||||
|
|
|
@ -27,7 +27,6 @@ class UserEmailNew extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<form
|
||||
className="form-input-width"
|
||||
onSubmit={event => {
|
||||
this.handleSubmit(event);
|
||||
}}
|
||||
|
|
|
@ -27,7 +27,6 @@ class UserEmailVerify extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<form
|
||||
className="form-input-width"
|
||||
onSubmit={event => {
|
||||
this.handleSubmit(event);
|
||||
}}
|
||||
|
|
21
ui/js/component/userVerify/index.js
Normal file
21
ui/js/component/userVerify/index.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doUserEmailVerify } from "actions/user";
|
||||
import {
|
||||
selectEmailVerifyIsPending,
|
||||
selectEmailToVerify,
|
||||
selectEmailVerifyErrorMessage,
|
||||
} from "selectors/user";
|
||||
import UserVerify from "./view";
|
||||
|
||||
const select = state => ({
|
||||
isPending: selectEmailVerifyIsPending(state),
|
||||
email: selectEmailToVerify(state),
|
||||
errorMessage: selectEmailVerifyErrorMessage(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
verifyUserEmail: code => dispatch(doUserEmailVerify(code)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(UserVerify);
|
69
ui/js/component/userVerify/view.jsx
Normal file
69
ui/js/component/userVerify/view.jsx
Normal file
|
@ -0,0 +1,69 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
import { FormRow } from "component/form.js";
|
||||
|
||||
class UserVerify extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
code: "",
|
||||
};
|
||||
}
|
||||
|
||||
handleCodeChanged(event) {
|
||||
this.setState({
|
||||
code: event.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
this.props.verifyUserEmail(this.state.code);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { errorMessage, isPending } = this.props;
|
||||
return <p>VERIFY</p>;
|
||||
return (
|
||||
<form
|
||||
onSubmit={event => {
|
||||
this.handleSubmit(event);
|
||||
}}
|
||||
>
|
||||
zzzzzzzzzzzzzzzzzzzzzzzzzzzzz
|
||||
<FormRow
|
||||
type="text"
|
||||
label={__("Verification Code")}
|
||||
placeholder="a94bXXXXXXXXXXXXXX"
|
||||
name="code"
|
||||
value={this.state.code}
|
||||
onChange={event => {
|
||||
this.handleCodeChanged(event);
|
||||
}}
|
||||
errorMessage={errorMessage}
|
||||
/>
|
||||
{/* render help separately so it always shows */}
|
||||
<div className="form-field__helper">
|
||||
<p>
|
||||
{__("Email")}{" "}
|
||||
<Link href="mailto:help@lbry.io" label="help@lbry.io" />{" "}
|
||||
{__("if you did not receive or are having trouble with your code.")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="form-row-submit form-row-submit--with-footer">
|
||||
<Link
|
||||
button="primary"
|
||||
label={__("Verify")}
|
||||
disabled={this.state.submitting}
|
||||
onClick={event => {
|
||||
this.handleSubmit(event);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default UserVerify;
|
|
@ -288,11 +288,6 @@ lbry.setClientSetting = function(setting, value) {
|
|||
return localStorage.setItem("setting_" + setting, JSON.stringify(value));
|
||||
};
|
||||
|
||||
//utilities
|
||||
lbry.formatCredits = function(amount, precision) {
|
||||
return amount.toFixed(precision || 1).replace(/\.?0+$/, "");
|
||||
};
|
||||
|
||||
lbry.formatName = function(name) {
|
||||
// Converts LBRY name to standard format (all lower case, no special characters, spaces replaced by dashes)
|
||||
name = name.replace("/s+/g", "-");
|
||||
|
|
|
@ -1,22 +1,31 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { selectFetchingRewards, selectRewards } from "selectors/rewards";
|
||||
import {
|
||||
makeSelectRewardByType,
|
||||
selectFetchingRewards,
|
||||
selectRewards,
|
||||
} from "selectors/rewards";
|
||||
import {
|
||||
selectUserIsRewardEligible,
|
||||
selectUserHasEmail,
|
||||
selectUserIsVerificationCandidate,
|
||||
} from "selectors/user";
|
||||
import { doRewardList } from "actions/rewards";
|
||||
import rewards from "rewards";
|
||||
import RewardsPage from "./view";
|
||||
|
||||
const select = state => ({
|
||||
fetching: selectFetchingRewards(state),
|
||||
rewards: selectRewards(state),
|
||||
hasEmail: selectUserHasEmail(state),
|
||||
isEligible: selectUserIsRewardEligible(state),
|
||||
isVerificationCandidate: selectUserIsVerificationCandidate(state),
|
||||
});
|
||||
const select = (state, props) => {
|
||||
const selectReward = makeSelectRewardByType();
|
||||
|
||||
return {
|
||||
fetching: selectFetchingRewards(state),
|
||||
rewards: selectRewards(state),
|
||||
hasEmail: selectUserHasEmail(state),
|
||||
isEligible: selectUserIsRewardEligible(state),
|
||||
isVerificationCandidate: selectUserIsVerificationCandidate(state),
|
||||
newUserReward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
||||
};
|
||||
};
|
||||
|
||||
const perform = dispatch => ({
|
||||
fetchRewards: () => dispatch(doRewardList()),
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
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 => {
|
||||
|
@ -41,7 +39,9 @@ class RewardsPage extends React.PureComponent {
|
|||
fetchRewards(props) {
|
||||
const { fetching, rewards, fetchRewards } = props;
|
||||
|
||||
if (!fetching && Object.keys(rewards).length < 1) fetchRewards();
|
||||
if (!fetching && (!rewards || !rewards.length)) {
|
||||
fetchRewards();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -51,6 +51,7 @@ class RewardsPage extends React.PureComponent {
|
|||
isVerificationCandidate,
|
||||
hasEmail,
|
||||
rewards,
|
||||
newUserReward,
|
||||
} = this.props;
|
||||
|
||||
let content,
|
||||
|
@ -59,42 +60,55 @@ class RewardsPage extends React.PureComponent {
|
|||
if (!hasEmail || isVerificationCandidate) {
|
||||
content = (
|
||||
<div>
|
||||
<p>
|
||||
{__(
|
||||
"Additional information is required to be eligible for the rewards program."
|
||||
)}
|
||||
</p>
|
||||
<Auth />
|
||||
<div className="card__title-primary">
|
||||
{newUserReward &&
|
||||
<CreditAmount amount={newUserReward.reward_amount} />}
|
||||
<h3>Welcome to LBRY</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<p>
|
||||
{" "}{__(
|
||||
"Claim your welcome credits to be able to publish content, pay creators, and have a say over the LBRY network."
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="card__content"><Auth /></div>
|
||||
</div>
|
||||
);
|
||||
isCard = true;
|
||||
} else if (!isEligible) {
|
||||
isCard = true;
|
||||
content = (
|
||||
<div className="empty">
|
||||
<div className="card__content empty">
|
||||
<p>{__("You are not eligible to claim rewards.")}</p>
|
||||
</div>
|
||||
);
|
||||
} else if (fetching) {
|
||||
content = <BusyMessage message={__("Fetching rewards")} />;
|
||||
content = (
|
||||
<div className="card__content">
|
||||
<BusyMessage message={__("Fetching rewards")} />
|
||||
</div>
|
||||
);
|
||||
} else if (rewards.length > 0) {
|
||||
content = rewards.map(reward =>
|
||||
<RewardTile key={reward.reward_type} reward={reward} />
|
||||
content = (
|
||||
<div>
|
||||
{rewards.map(reward =>
|
||||
<RewardTile key={reward.reward_type} reward={reward} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
content = <div className="empty">{__("Failed to load rewards.")}</div>;
|
||||
content = (
|
||||
<div className="card__content empty">
|
||||
{__("Failed to load rewards.")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="main--single-column">
|
||||
<SubHeader />
|
||||
{isCard
|
||||
? <section className="card">
|
||||
<div className="card__content">
|
||||
{content}
|
||||
</div>
|
||||
</section>
|
||||
: content}
|
||||
{isCard ? <section className="card">{content}</section> : content}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,10 +12,7 @@ export const selectUserIsPending = createSelector(
|
|||
state => state.userIsPending
|
||||
);
|
||||
|
||||
export const selectUser = createSelector(
|
||||
_selectState,
|
||||
state => state.user || {}
|
||||
);
|
||||
export const selectUser = createSelector(_selectState, state => state.user);
|
||||
|
||||
export const selectEmailToVerify = createSelector(
|
||||
_selectState,
|
||||
|
@ -65,7 +62,7 @@ export const selectEmailVerifyErrorMessage = createSelector(
|
|||
|
||||
export const selectUserIsVerificationCandidate = createSelector(
|
||||
selectUser,
|
||||
user => user && !user.has_verified_email
|
||||
user => user && (!user.has_verified_email || !user.is_identity_verified)
|
||||
);
|
||||
|
||||
export const selectUserIsAuthRequested = createSelector(
|
||||
|
|
|
@ -29,3 +29,7 @@ export function getSession(key, fallback = undefined) {
|
|||
export function setSession(key, value) {
|
||||
sessionStorage.setItem(key, JSON.stringify(value));
|
||||
}
|
||||
|
||||
export function formatCredits(amount, precision) {
|
||||
return amount.toFixed(precision || 1).replace(/\.?0+$/, "");
|
||||
}
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
$width-input-border: 2px;
|
||||
$width-input-text: 330px;
|
||||
|
||||
.form-input-width {
|
||||
width: $width-input-text
|
||||
}
|
||||
|
||||
.form-row-submit
|
||||
{
|
||||
margin-top: $spacing-vertical;
|
||||
|
|
Loading…
Add table
Reference in a new issue