Merge branch 'first_run_email'

This commit is contained in:
Jeremy Kauffman 2017-12-08 15:13:41 -05:00
commit f1f3d311e9
40 changed files with 297 additions and 264 deletions

View file

@ -9,9 +9,11 @@ Web UI version numbers should always match the corresponding version of LBRY App
## [Unreleased]
### Added
* ShapeShift integration
*
### Changed
* The first run process for new users has changed substantially. New users can now easily receive one credit.
* The wallet area has been re-organized. Send and Receive are now on the same page. A new page, "Get Credits", explains how users can add LBRY credits to the app.
* The prompt for an insufficient balance is much more user-friendly.
* The credit balance displayed in the main app navigation displays two decimal places instead of one.
* Moved all redux code into /redux folder
* Channel names in pages are highlighted to indicate them being clickable(#814)
@ -27,7 +29,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
*
### Deprecated
*
* We previous two separate modals for insufficient credits. These have been combined.
*
### Removed

View file

@ -3,7 +3,7 @@ import Router from "component/router/index";
import Header from "component/header";
import Theme from "component/theme";
import ModalRouter from "modal/modalRouter";
import lbry from "lbry";
import ReactModal from "react-modal";
import throttle from "util/throttle";
class App extends React.PureComponent {
@ -28,6 +28,8 @@ class App extends React.PureComponent {
const scrollListener = () => recordScroll(this.mainContent.scrollTop);
this.mainContent.addEventListener("scroll", throttle(scrollListener, 750));
ReactModal.setAppElement("#window"); //fuck this
}
componentWillUnmount() {

View file

@ -69,7 +69,7 @@ export class CreditAmount extends React.PureComponent {
amount: PropTypes.number.isRequired,
precision: PropTypes.number,
isEstimate: PropTypes.bool,
label: PropTypes.bool,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
showFree: PropTypes.bool,
showFullPrice: PropTypes.bool,
showPlus: PropTypes.bool,
@ -106,10 +106,12 @@ export class CreditAmount extends React.PureComponent {
amountText = __("free");
} else {
if (this.props.label) {
amountText =
formattedAmount +
" " +
(parseFloat(amount) == 1 ? __("credit") : __("credits"));
const label =
typeof this.props.label === "string"
? this.props.label
: parseFloat(amount) == 1 ? __("credit") : __("credits");
amountText = formattedAmount + " " + label;
} else {
amountText = formattedAmount;
}

View file

@ -882,6 +882,7 @@ class PublishForm extends React.PureComponent {
!this.state.submitting ? __("Publish") : __("Publishing...")
}
disabled={
this.props.balance <= 0 ||
this.state.submitting ||
(this.state.uri &&
this.props.resolvingUris.indexOf(this.state.uri) !== -1) ||

View file

@ -20,7 +20,11 @@ const RewardSummary = props => {
)}
</div>
<div className="card__actions">
<Link button="alt" navigate="/rewards" label={__("Learn more")} />
<Link
button="primary"
navigate="/rewards"
label={__("Claim Rewards")}
/>
</div>
</section>
);

View file

@ -3,8 +3,8 @@ import SettingsPage from "page/settings";
import HelpPage from "page/help";
import ReportPage from "page/report.js";
import WalletPage from "page/wallet";
import ReceiveCreditsPage from "page/receiveCredits";
import SendCreditsPage from "page/sendCredits";
import GetCreditsPage from "../../page/getCredits";
import SendReceivePage from "page/sendCredits";
import ShowPage from "page/show";
import PublishPage from "page/publish";
import DiscoverPage from "page/discover";
@ -38,11 +38,11 @@ const Router = props => {
invite: <InvitePage params={params} />,
publish: <PublishPage params={params} />,
published: <FileListPublished params={params} />,
receive: <ReceiveCreditsPage params={params} />,
getcredits: <GetCreditsPage params={params} />,
report: <ReportPage params={params} />,
rewards: <RewardsPage params={params} />,
search: <SearchPage params={params} />,
send: <SendCreditsPage params={params} />,
send: <SendReceivePage params={params} />,
settings: <SettingsPage params={params} />,
show: <ShowPage {...params} />,
wallet: <WalletPage params={params} />,

View file

@ -6,10 +6,15 @@ import {
selectEmailNewErrorMessage,
} from "redux/selectors/user";
import UserEmailNew from "./view";
import rewards from "rewards";
import { makeSelectRewardAmountByType } from "redux/selectors/rewards";
const select = state => ({
isPending: selectEmailNewIsPending(state),
errorMessage: selectEmailNewErrorMessage(state),
rewardAmount: makeSelectRewardAmountByType()(state, {
reward_type: rewards.TYPE_CONFIRM_EMAIL,
}),
});
const perform = dispatch => ({

View file

@ -1,5 +1,5 @@
import React from "react";
import Link from "component/link";
import { CreditAmount } from "component/common";
import { Form, FormRow, Submit } from "component/form.js";
class UserEmailNew extends React.PureComponent {
@ -23,35 +23,41 @@ class UserEmailNew extends React.PureComponent {
}
render() {
const { errorMessage, isPending } = this.props;
const { cancelButton, errorMessage, isPending, rewardAmount } = this.props;
return (
<Form onSubmit={this.handleSubmit.bind(this)}>
<div>
<p>
{__(
"This process is required to prevent abuse of the rewards program."
)}
Let us know your email and you'll receive{" "}
<CreditAmount amount={rewardAmount} label="LBC" />, the blockchain
token used by LBRY.
</p>
<p>
{__(
"We will also contact you about updates and new content, but you can unsubscribe at any time."
"We'll also let you know about LBRY updates, security issues, and great new content."
)}
</p>
<FormRow
type="text"
label="Email"
placeholder="youremail@example.org"
name="email"
value={this.state.email}
errorMessage={errorMessage}
onChange={event => {
this.handleEmailChanged(event);
}}
/>
<div className="form-row-submit">
<Submit label="Next" disabled={isPending} />
</div>
</Form>
<p>
{__("We'll never sell your email, and you can unsubscribe at any time.")}
</p>
<Form onSubmit={this.handleSubmit.bind(this)}>
<FormRow
type="text"
label="Email"
placeholder="youremail@example.org"
name="email"
value={this.state.email}
errorMessage={errorMessage}
onChange={event => {
this.handleEmailChanged(event);
}}
/>
<div className="form-row-submit">
<Submit label="Submit" disabled={isPending} />
{cancelButton}
</div>
</Form>
</div>
);
}
}

View file

@ -7,11 +7,16 @@ import {
selectEmailVerifyErrorMessage,
} from "redux/selectors/user";
import UserEmailVerify from "./view";
import rewards from "rewards";
import { makeSelectRewardAmountByType } from "redux/selectors/rewards";
const select = state => ({
isPending: selectEmailVerifyIsPending(state),
email: selectEmailToVerify(state),
errorMessage: selectEmailVerifyErrorMessage(state),
rewardAmount: makeSelectRewardAmountByType()(state, {
reward_type: rewards.TYPE_CONFIRM_EMAIL,
}),
});
const perform = dispatch => ({

View file

@ -1,5 +1,6 @@
import React from "react";
import Link from "component/link";
import { CreditAmount } from "component/common";
import { Form, FormRow, Submit } from "component/form.js";
class UserEmailVerify extends React.PureComponent {
@ -23,10 +24,16 @@ class UserEmailVerify extends React.PureComponent {
}
render() {
const { errorMessage, isPending } = this.props;
const {
cancelButton,
errorMessage,
email,
isPending,
rewardAmount,
} = this.props;
return (
<Form onSubmit={this.handleSubmit.bind(this)}>
<p>{__("Please enter the verification code emailed to you.")}</p>
<p>Please enter the verification code emailed to {email}.</p>
<FormRow
type="text"
label={__("Verification Code")}
@ -41,12 +48,14 @@ class UserEmailVerify extends React.PureComponent {
<div className="form-field__helper">
<p>
{__("Email")}{" "}
<Link href="mailto:help@lbry.io" label="help@lbry.io" />{" "}
<Link href="mailto:help@lbry.io" label="help@lbry.io" /> or join our{" "}
<Link href="https://chat.lbry.io" label="chat" />{" "}
{__("if you encounter any trouble with your code.")}
</p>
</div>
<div className="form-row-submit form-row-submit--with-footer">
<Submit label={__("Verify")} disabled={this.state.submitting} />
<div className="form-row-submit">
<Submit label={__("Verify")} disabled={isPending} />
{cancelButton}
</div>
</Form>
);

View file

@ -79,9 +79,16 @@ class UserVerify extends React.PureComponent {
<div className="card__content">
<p>
{__(
"If you have a YouTube account with subscribers and views, you can sync your account to be granted instant verification."
"If you have a YouTube account with subscribers and views, you can sync your account and content to be granted instant verification."
)}
</p>
<p>
{__("Some account minimums apply.")}{" "}
<Link
href="https://lbry.io/faq/youtube"
label={__("Read more.")}
/>
</p>
</div>
<div className="card__actions">
<Link

View file

@ -23,11 +23,12 @@ const WalletBalance = props => {
)}
</div>
<div className="card__actions">
<Link button="alt" navigate="/getcredits" label={__("Get Credits")} />
<Link
button="primary"
button="alt"
disabled={balance === 0}
navigate="/backup"
label={__("Backup wallet")}
label={__("Backup Wallet")}
/>
</div>
</section>

View file

@ -6,11 +6,10 @@ export const ERROR = "error";
export const INSUFFICIENT_CREDITS = "insufficient_credits";
export const UPGRADE = "upgrade";
export const WELCOME = "welcome";
export const EMAIL_COLLECTION = "email_collection";
export const FIRST_REWARD = "first_reward";
export const AUTHENTICATION_FAILURE = "auth_failure";
export const TRANSACTION_FAILED = "transaction_failed";
export const INSUFFICIENT_BALANCE = "insufficient_balance";
export const REWARD_APPROVAL_REQUIRED = "reward_approval_required";
export const AFFIRM_PURCHASE = "affirm_purchase";
export const CREDIT_INTRO = "credit_intro";
export const CONFIRM_CLAIM_REVOKE = "confirmClaimRevoke";

View file

@ -1,8 +1,9 @@
/*hardcoded names still exist for these in reducers/settings.js - only discovered when debugging*/
/*Many settings are stored in the localStorage by their name -
be careful about changing the value of a settings constant, as doing so can invalidate existing settings*/
export const CREDIT_INTRO_ACKNOWLEDGED = "credit_intro_acknowledged";
export const CREDIT_REQUIRED_ACKNOWLEDGED = "credit_required_acknowledged";
export const NEW_USER_ACKNOWLEDGED = "welcome_acknowledged";
export const EMAIL_COLLECTION_ACKNOWLEDGED = "email_collection_acknowledged";
export const LANGUAGE = "language";
export const SHOW_NSFW = "showNsfw";
export const SHOW_UNAVAILABLE = "showUnavailable";

View file

@ -61,7 +61,7 @@ document.addEventListener("click", event => {
if (target.matches("a") || target.matches("button")) {
// TODO: Look into using accessiblity labels (this would also make the app more accessible)
let hrefParts = window.location.href.split("#");
let element = target.title || target.text.trim();
let element = target.title || (target.text && target.text.trim());
if (element) {
amplitude.getInstance().logEvent("CLICK", {
target: element,

View file

@ -1,7 +1,7 @@
import React from "react";
import { connect } from "react-redux";
import { doCloseModal } from "redux/actions/app";
import { doAuthNavigate } from "redux/actions/navigation";
import { doNavigate } from "redux/actions/navigation";
import { doSetClientSetting } from "redux/actions/settings";
import { selectUserIsRewardApproved } from "redux/selectors/user";
import { selectBalance } from "redux/selectors/wallet";
@ -25,17 +25,16 @@ const select = (state, props) => {
};
const perform = dispatch => () => {
const closeModal = () => {
dispatch(doSetClientSetting(settings.CREDIT_INTRO_ACKNOWLEDGED, true));
dispatch(doCloseModal());
};
return {
verifyAccount: () => {
closeModal();
dispatch(doAuthNavigate("/discover"));
addBalance: () => {
dispatch(doSetClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED, true));
dispatch(doNavigate("/getcredits"));
dispatch(doCloseModal());
},
closeModal: () => {
dispatch(doSetClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED, true));
dispatch(doCloseModal());
},
closeModal: closeModal,
};
};

View file

@ -4,55 +4,42 @@ import { CreditAmount, CurrencySymbol } from "component/common";
import Link from "component/link/index";
const ModalCreditIntro = props => {
const { closeModal, totalRewardValue, currentBalance, verifyAccount } = props;
const { closeModal, totalRewardValue, currentBalance, addBalance } = props;
const totalRewardRounded = Math.round(totalRewardValue / 10) * 10;
return (
<Modal type="custom" isOpen={true} contentLabel="Welcome to LBRY">
<section>
<h3 className="modal__header">{__("Blockchain 101")}</h3>
<h3 className="modal__header">
{__("Computer Wizard Needs Tokens Badly")}
</h3>
<p>
LBRY is controlled and powered by a blockchain asset called{" "}
<em>
Some actions require{" "} LBRY credits
(<em>
<CurrencySymbol />
</em>. <CurrencySymbol />{" "}
{__(
"is used to publish content, to have a say in the network rules, and to access paid content."
)}
</em>), the blockchain token that powers the LBRY network.
</p>
{currentBalance <= 0 ? (
<div>
<p>
You currently have <CreditAmount amount={currentBalance} />, so
the actions you can take are limited.
</p>
<p>
However, there are a variety of ways to get credits, including
more than{" "}
{totalRewardValue ? (
<CreditAmount amount={totalRewardRounded} />
) : (
<span className="credit-amount">{__("?? credits")}</span>
)}{" "}
{__(
" in rewards available for being a proven human during the LBRY beta."
)}
</p>
</div>
) : (
<div>
<p>
But you probably knew this, since you've already got{" "}
<CreditAmount amount={currentBalance} />.
</p>
</div>
{currentBalance <= 0 && (
<p>
You currently have <CreditAmount amount={currentBalance} />, so the
actions you can take are limited.
</p>
)}
<p>
There are a variety of ways to get credits, including more than{" "}
{totalRewardValue ? (
<CreditAmount amount={totalRewardRounded} />
) : (
<span className="credit-amount">{__("?? credits")}</span>
)}{" "}
{__(" in free rewards for participating in the LBRY beta.")}
</p>
<div className="modal__buttons">
<Link
button="primary"
onClick={verifyAccount}
label={__("I'm Totally A Human")}
onClick={addBalance}
label={__("Get Credits")}
/>
<Link
button="alt"

View file

@ -0,0 +1,21 @@
import React from "react";
import * as settings from "constants/settings";
import { connect } from "react-redux";
import { doCloseModal } from "redux/actions/app";
import { doSetClientSetting } from "redux/actions/settings";
import { selectEmailToVerify, selectUser } from "redux/selectors/user";
import ModalEmailCollection from "./view";
const select = state => ({
email: selectEmailToVerify(state),
user: selectUser(state),
});
const perform = dispatch => () => ({
closeModal: () => {
dispatch(doSetClientSetting(settings.EMAIL_COLLECTION_ACKNOWLEDGED, true));
dispatch(doCloseModal());
},
});
export default connect(select, perform)(ModalEmailCollection);

View file

@ -0,0 +1,45 @@
import React from "react";
import { Modal } from "modal/modal";
import Link from "component/link/index";
import UserEmailNew from "component/userEmailNew";
import UserEmailVerify from "component/userEmailVerify";
class ModalEmailCollection extends React.PureComponent {
renderInner() {
const { closeModal, email, user } = this.props;
const cancelButton = (
<Link button="text" onClick={closeModal} label={__("Not Now")} />
);
if (!user.has_verified_email && !email) {
return <UserEmailNew cancelButton={cancelButton} />;
} else if (!user.has_verified_email) {
return <UserEmailVerify cancelButton={cancelButton} />;
} else {
closeModal();
}
}
render() {
const { user } = this.props;
//this shouldn't happen
if (!user) {
return null;
}
return (
<Modal type="custom" isOpen={true} contentLabel="Email">
<section>
<h3 className="modal__header">
Can We <strike>Touch You</strike> Stay In Touch?
</h3>
{this.renderInner()}
</section>
</Modal>
);
}
}
export default ModalEmailCollection;

View file

@ -32,12 +32,7 @@ class ModalFirstReward extends React.PureComponent {
</p>
<p>
{__(
"No need to understand it all just yet! Try watching or downloading something next."
)}
</p>
<p>
{__(
"Finally, please know that LBRY is an early beta and that it earns the name."
"No need to understand it all just yet! Try watching or publishing something next."
)}
</p>
</section>

View file

@ -1,17 +0,0 @@
import React from "react";
import { connect } from "react-redux";
import { doCloseModal } from "redux/actions/app";
import { doNavigate } from "redux/actions/navigation";
import ModalInsufficientBalance from "./view";
const select = state => ({});
const perform = dispatch => ({
addBalance: () => {
dispatch(doNavigate("/wallet"));
dispatch(doCloseModal());
},
closeModal: () => dispatch(doCloseModal()),
});
export default connect(select, perform)(ModalInsufficientBalance);

View file

@ -1,26 +0,0 @@
import React from "react";
import { Modal } from "modal/modal";
class ModalInsufficientBalance extends React.PureComponent {
render() {
const { addBalance, closeModal } = this.props;
return (
<Modal
isOpen={true}
type="confirm"
contentLabel={__("Not enough credits")}
confirmButtonLabel={__("Get Credits")}
abortButtonLabel={__("Cancel")}
onAborted={closeModal}
onConfirmed={addBalance}
>
{__(
"Insufficient balance: after this transaction you would have less than 0 LBCs in your wallet."
)}
</Modal>
);
}
}
export default ModalInsufficientBalance;

View file

@ -1,17 +0,0 @@
import React from "react";
import { connect } from "react-redux";
import { doCloseModal } from "redux/actions/app";
import { doNavigate } from "redux/actions/navigation";
import ModalInsufficientCredits from "./view";
const select = state => ({});
const perform = dispatch => ({
addFunds: () => {
dispatch(doNavigate("/wallet"));
dispatch(doCloseModal());
},
closeModal: () => dispatch(doCloseModal()),
});
export default connect(select, perform)(ModalInsufficientCredits);

View file

@ -1,28 +0,0 @@
import React from "react";
import { Modal } from "modal/modal";
import { CurrencySymbol } from "component/common";
class ModalInsufficientCredits extends React.PureComponent {
render() {
const { addFunds, closeModal } = this.props;
return (
<Modal
isOpen={true}
type="confirm"
contentLabel={__("Not enough credits")}
confirmButtonLabel={__("Get Credits")}
abortButtonLabel={__("Not Now")}
onAborted={closeModal}
onConfirmed={addFunds}
>
<h3 className="modal__header">{__("More Credits Required")}</h3>
<p>
You'll need more <CurrencySymbol /> to do this.
</p>
</Modal>
);
}
}
export default ModalInsufficientCredits;

View file

@ -6,8 +6,12 @@ import { selectCurrentModal, selectModalProps } from "redux/selectors/app";
import { selectCurrentPage } from "redux/selectors/navigation";
import { selectCostForCurrentPageUri } from "redux/selectors/cost_info";
import { makeSelectClientSetting } from "redux/selectors/settings";
import { selectUser } from "redux/selectors/user";
import {
selectUser,
selectUserIsVerificationCandidate,
} from "redux/selectors/user";
import { selectBalance } from "redux/selectors/wallet";
import ModalRouter from "./view";
const select = (state, props) => ({
@ -16,12 +20,16 @@ const select = (state, props) => ({
modal: selectCurrentModal(state),
modalProps: selectModalProps(state),
page: selectCurrentPage(state),
isVerificationCandidate: selectUserIsVerificationCandidate(state),
isCreditIntroAcknowledged: makeSelectClientSetting(
settings.CREDIT_REQUIRED_ACKNOWLEDGED
)(state),
isEmailCollectionAcknowledged: makeSelectClientSetting(
settings.EMAIL_COLLECTION_ACKNOWLEDGED
)(state),
isWelcomeAcknowledged: makeSelectClientSetting(
settings.NEW_USER_ACKNOWLEDGED
)(state),
isCreditIntroAcknowledged: makeSelectClientSetting(
settings.CREDIT_INTRO_ACKNOWLEDGED
)(state),
user: selectUser(state),
});

View file

@ -2,7 +2,6 @@ import React from "react";
import ModalError from "modal/modalError";
import ModalAuthFailure from "modal/modalAuthFailure";
import ModalDownloading from "modal/modalDownloading";
import ModalInsufficientCredits from "modal/modalInsufficientCredits";
import ModalUpgrade from "modal/modalUpgrade";
import ModalWelcome from "modal/modalWelcome";
import ModalFirstReward from "modal/modalFirstReward";
@ -10,10 +9,10 @@ import ModalRewardApprovalRequired from "modal/modalRewardApprovalRequired";
import ModalCreditIntro from "modal/modalCreditIntro";
import ModalRemoveFile from "modal/modalRemoveFile";
import ModalTransactionFailed from "modal/modalTransactionFailed";
import ModalInsufficientBalance from "modal/modalInsufficientBalance";
import ModalFileTimeout from "modal/modalFileTimeout";
import ModalAffirmPurchase from "modal/modalAffirmPurchase";
import ModalRevokeClaim from "modal/modalRevokeClaim";
import ModalEmailCollection from "../modalEmailCollection";
import * as modals from "constants/modal_types";
class ModalRouter extends React.PureComponent {
@ -43,8 +42,8 @@ class ModalRouter extends React.PureComponent {
const transitionModal = [
this.checkShowWelcome,
this.checkShowEmail,
this.checkShowCreditIntro,
this.checkShowInsufficientCredits,
].reduce((acc, func) => {
return !acc ? func.bind(this)(props) : acc;
}, false);
@ -74,24 +73,30 @@ class ModalRouter extends React.PureComponent {
}
}
checkShowCreditIntro(props) {
const { page, isCreditIntroAcknowledged, user } = props;
checkShowEmail(props) {
const {
isEmailCollectionAcknowledged,
isVerificationCandidate,
user,
} = props;
if (
!isCreditIntroAcknowledged &&
!isEmailCollectionAcknowledged &&
isVerificationCandidate &&
user &&
!user.is_reward_approved &&
(["rewards", "send", "receive", "publish", "wallet"].includes(page) ||
this.isPaidShowPage(props))
!user.has_verified_email
) {
return modals.CREDIT_INTRO;
return modals.EMAIL_COLLECTION;
}
}
checkShowInsufficientCredits(props) {
const { balance, page } = props;
checkShowCreditIntro(props) {
const { balance, page, isCreditIntroAcknowledged } = props;
if (balance <= 0 && ["send", "publish"].includes(page)) {
if (
balance <= 0 &&
!isCreditIntroAcknowledged &&
(["send", "publish"].includes(page) || this.isPaidShowPage(props))
) {
return modals.INSUFFICIENT_CREDITS;
}
}
@ -114,19 +119,15 @@ class ModalRouter extends React.PureComponent {
case modals.FILE_TIMEOUT:
return <ModalFileTimeout {...modalProps} />;
case modals.INSUFFICIENT_CREDITS:
return <ModalInsufficientCredits {...modalProps} />;
return <ModalCreditIntro {...modalProps} />;
case modals.WELCOME:
return <ModalWelcome {...modalProps} />;
case modals.FIRST_REWARD:
return <ModalFirstReward {...modalProps} />;
case modals.AUTHENTICATION_FAILURE:
return <ModalAuthFailure {...modalProps} />;
case modals.CREDIT_INTRO:
return <ModalCreditIntro {...modalProps} />;
case modals.TRANSACTION_FAILED:
return <ModalTransactionFailed {...modalProps} />;
case modals.INSUFFICIENT_BALANCE:
return <ModalInsufficientBalance {...modalProps} />;
case modals.REWARD_APPROVAL_REQUIRED:
return <ModalRewardApprovalRequired {...modalProps} />;
case modals.CONFIRM_FILE_REMOVE:
@ -135,6 +136,8 @@ class ModalRouter extends React.PureComponent {
return <ModalAffirmPurchase {...modalProps} />;
case modals.CONFIRM_CLAIM_REVOKE:
return <ModalRevokeClaim {...modalProps} />;
case modals.EMAIL_COLLECTION:
return <ModalEmailCollection {...modalProps} />;
default:
return null;
}

View file

@ -0,0 +1,5 @@
import React from "react";
import { connect } from "react-redux";
import GetCreditsPage from "./view";
export default connect(null, null)(GetCreditsPage);

View file

@ -1,15 +1,28 @@
import React from "react";
import SubHeader from "component/subHeader";
import Link from "component/link";
import WalletAddress from "component/walletAddress";
import RewardSummary from "component/rewardSummary";
import ShapeShift from "component/shapeShift";
const ReceiveCreditsPage = props => {
const GetCreditsPage = props => {
return (
<main className="main--single-column">
<SubHeader />
<WalletAddress />
<RewardSummary />
<ShapeShift />
<section className="card">
<div className="card__title-primary">
<h3>{__("From External Wallet")}</h3>
</div>
<div className="card__actions">
<Link
button="alt"
navigate="/send"
icon="icon-send"
label={__("Send / Receive")}
/>
</div>
</section>
<section className="card">
<div className="card__title-primary">
<h3>{__("More ways to get LBRY Credits")}</h3>
@ -33,4 +46,4 @@ const ReceiveCreditsPage = props => {
);
};
export default ReceiveCreditsPage;
export default GetCreditsPage;

View file

@ -1,5 +0,0 @@
import React from "react";
import { connect } from "react-redux";
import ReceiveCreditsPage from "./view";
export default connect(null, null)(ReceiveCreditsPage);

View file

@ -1,5 +1,5 @@
import React from "react";
import { connect } from "react-redux";
import SendCreditsPage from "./view";
import SendReceivePage from "./view";
export default connect(null, null)(SendCreditsPage);
export default connect(null, null)(SendReceivePage);

View file

@ -1,14 +1,16 @@
import React from "react";
import SubHeader from "component/subHeader";
import WalletSend from "component/walletSend";
import WalletAddress from "component/walletAddress";
const SendCreditsPage = props => {
const SendReceivePage = props => {
return (
<main className="main--single-column">
<SubHeader />
<WalletSend />
<WalletAddress />
</main>
);
};
export default SendCreditsPage;
export default SendReceivePage;

View file

@ -4,6 +4,7 @@ import lbryio from "lbryio";
import rewards from "rewards";
import { selectUnclaimedRewardsByType } from "redux/selectors/rewards";
import { selectUserIsRewardApproved } from "redux/selectors/user";
import { selectClaimedRewardsById } from "../selectors/rewards";
export function doRewardList() {
return function(dispatch, getState) {
@ -42,7 +43,7 @@ export function doClaimRewardType(rewardType) {
return;
}
if (!userIsRewardApproved) {
if (!userIsRewardApproved && rewardType !== rewards.TYPE_CONFIRM_EMAIL) {
return dispatch({
type: types.OPEN_MODAL,
data: { modal: modals.REWARD_APPROVAL_REQUIRED },
@ -61,7 +62,7 @@ export function doClaimRewardType(rewardType) {
reward,
},
});
if (reward.reward_type == rewards.TYPE_NEW_USER) {
if (reward.reward_type == rewards.TYPE_CONFIRM_EMAIL) {
dispatch({
type: types.OPEN_MODAL,
data: { modal: modals.FIRST_REWARD },

View file

@ -61,6 +61,22 @@ export function doUserEmailNew(email) {
type: types.USER_EMAIL_NEW_STARTED,
email: email,
});
const success = () => {
dispatch({
type: types.USER_EMAIL_NEW_SUCCESS,
data: { email },
});
dispatch(doUserFetch());
}
const failure = error => {
dispatch({
type: types.USER_EMAIL_NEW_FAILURE,
data: { error },
});
}
lbryio
.call(
"user_email",
@ -75,23 +91,11 @@ export function doUserEmailNew(email) {
"resend_token",
{ email: email, only_if_expired: true },
"post"
);
).then(success, failure);
}
throw error;
})
.then(() => {
dispatch({
type: types.USER_EMAIL_NEW_SUCCESS,
data: { email },
});
dispatch(doUserFetch());
})
.catch(error => {
dispatch({
type: types.USER_EMAIL_NEW_FAILURE,
data: { error },
});
});
.then(success, failure);
};
}
@ -118,7 +122,8 @@ export function doUserEmailVerify(verificationToken) {
type: types.USER_EMAIL_VERIFY_SUCCESS,
data: { email },
});
dispatch(doUserFetch());
dispatch(doClaimRewardType(rewards.TYPE_CONFIRM_EMAIL)),
dispatch(doUserFetch());
} else {
throw new Error("Your email is still not verified."); //shouldn't happen
}

View file

@ -97,7 +97,7 @@ export function doSendDraftTransaction() {
const amount = selectDraftTransactionAmount(state);
if (balance - amount <= 0) {
return dispatch(doOpenModal(modals.INSUFFICIENT_BALANCE));
return dispatch(doOpenModal(modals.INSUFFICIENT_CREDITS));
}
dispatch({
@ -162,7 +162,7 @@ export function doSendSupport(amount, claim_id, uri) {
const balance = selectBalance(state);
if (balance - amount <= 0) {
return dispatch(doOpenModal(modals.INSUFFICIENT_BALANCE));
return dispatch(doOpenModal(modals.INSUFFICIENT_CREDITS));
}
dispatch({

View file

@ -24,9 +24,10 @@ const defaultState = {
settings.NEW_USER_ACKNOWLEDGED,
false
),
credit_intro_acknowledged: getLocalStorageSetting(
settings.CREDIT_INTRO_ACKNOWLEDGED
email_collection_acknowledged: getLocalStorageSetting(
settings.EMAIL_COLLECTION_ACKNOWLEDGED
),
credit_required_acknowledged: false, //this needs to be re-acknowledged every run
language: getLocalStorageSetting(settings.LANGUAGE, "en"),
theme: getLocalStorageSetting(settings.THEME, "light"),
themes: getLocalStorageSetting(settings.THEMES, []),

View file

@ -37,17 +37,17 @@ export const selectHeaderLinks = createSelector(selectCurrentPage, page => {
case "wallet":
case "history":
case "send":
case "receive":
case "getcredits":
case "invite":
case "rewards":
case "backup":
return {
wallet: __("Overview"),
history: __("History"),
send: __("Send Credits"),
receive: __("Get Credits"),
getcredits: __("Get Credits"),
send: __("Send / Receive"),
rewards: __("Rewards"),
invite: __("Invites"),
history: __("History"),
};
case "downloaded":
case "published":
@ -78,8 +78,8 @@ export const selectPageTitle = createSelector(
case "wallet":
return __("Wallet");
case "send":
return __("Send LBRY Credits");
case "receive":
return __("Send or Receive LBRY Credits");
case "getcredits":
return __("Get LBRY Credits");
case "backup":
return __("Backup Your Wallet");

View file

@ -63,9 +63,8 @@ export const selectWunderBarIcon = createSelector(
return "icon-rocket";
case "invite":
return "icon-envelope-open";
case "address":
case "receive":
return "icon-credit-card";
case "getcredits":
return "icon-shopping-cart";
case "wallet":
case "backup":
return "icon-bank";

View file

@ -14,16 +14,17 @@ export const selectUserIsPending = createSelector(
export const selectUser = createSelector(_selectState, state => state.user);
export const selectEmailToVerify = createSelector(
_selectState,
state => state.emailToVerify
);
export const selectUserEmail = createSelector(
selectUser,
user => (user ? user.primary_email : null)
);
export const selectEmailToVerify = createSelector(
_selectState,
selectUserEmail,
(state, userEmail) => state.emailToVerify || userEmail
);
export const selectUserIsRewardApproved = createSelector(
selectUser,
user => user && user.is_reward_approved

View file

@ -33,10 +33,7 @@ function rewardMessage(type, amount) {
"You earned %s LBC for watching a featured download.",
amount
),
referral: __(
"You earned %s LBC for referring someone.",
amount
),
referral: __("You earned %s LBC for referring someone.", amount),
}[type];
}
@ -44,7 +41,7 @@ const rewards = {};
rewards.TYPE_NEW_DEVELOPER = "new_developer";
rewards.TYPE_NEW_USER = "new_user";
rewards.TYPE_CONFIRM_EMAIL = "confirm_email";
rewards.TYPE_CONFIRM_EMAIL = "verified_email";
rewards.TYPE_FIRST_CHANNEL = "new_channel";
rewards.TYPE_FIRST_STREAM = "first_stream";
rewards.TYPE_MANY_DOWNLOADS = "many_downloads";

View file

@ -128,7 +128,7 @@ $text-color: #000;
--card-small-width: $spacing-vertical * 10;
/* Modal */
--modal-width: 420px;
--modal-width: 440px;
--modal-bg: var(--color-bg);
--modal-overlay-bg: rgba(#F5F5F5, 0.75); // --color-canvas: #F5F5F5
--modal-border: 1px solid rgb(204, 204, 204);