Merge branch 'first_run_email'
This commit is contained in:
commit
f1f3d311e9
40 changed files with 297 additions and 264 deletions
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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} />,
|
||||
|
|
|
@ -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 => ({
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 => ({
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
21
src/renderer/modal/modalEmailCollection/index.js
Normal file
21
src/renderer/modal/modalEmailCollection/index.js
Normal 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);
|
45
src/renderer/modal/modalEmailCollection/view.jsx
Normal file
45
src/renderer/modal/modalEmailCollection/view.jsx
Normal 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;
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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),
|
||||
});
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
5
src/renderer/page/getCredits/index.js
Normal file
5
src/renderer/page/getCredits/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import GetCreditsPage from "./view";
|
||||
|
||||
export default connect(null, null)(GetCreditsPage);
|
|
@ -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;
|
|
@ -1,5 +0,0 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import ReceiveCreditsPage from "./view";
|
||||
|
||||
export default connect(null, null)(ReceiveCreditsPage);
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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, []),
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue