diff --git a/ui/js/actions/app.js b/ui/js/actions/app.js
index 871607778..e6d5879f8 100644
--- a/ui/js/actions/app.js
+++ b/ui/js/actions/app.js
@@ -4,7 +4,6 @@ import {
selectUpdateUrl,
selectUpgradeDownloadPath,
selectUpgradeDownloadItem,
- selectUpgradeFilename,
selectPageTitle,
selectCurrentPage,
selectCurrentParams,
@@ -35,6 +34,20 @@ export function doNavigate(path, params = {}) {
};
}
+export function doAuthNavigate(pathAfterAuth = null, params = {}) {
+ return function(dispatch, getState) {
+ if (pathAfterAuth) {
+ dispatch({
+ type: types.CHANGE_AFTER_AUTH_PATH,
+ data: {
+ path: `${pathAfterAuth}?${toQueryString(params)}`,
+ },
+ });
+ }
+ dispatch(doNavigate("/auth"));
+ };
+}
+
export function doChangePath(path, options = {}) {
return function(dispatch, getState) {
dispatch({
@@ -237,8 +250,6 @@ export function doCheckDaemonVersion() {
export function doAlertError(errorList) {
return function(dispatch, getState) {
const state = getState();
- console.log("do alert error");
- console.log(errorList);
dispatch({
type: types.OPEN_MODAL,
data: {
diff --git a/ui/js/actions/content.js b/ui/js/actions/content.js
index 6c2052aca..b0e40ffa8 100644
--- a/ui/js/actions/content.js
+++ b/ui/js/actions/content.js
@@ -15,8 +15,8 @@ import { selectBadgeNumber } from "selectors/app";
import { selectTotalDownloadProgress } from "selectors/file_info";
import setBadge from "util/setBadge";
import setProgressBar from "util/setProgressBar";
-import { doFileList } from "actions/file_info";
import batchActions from "util/batchActions";
+import * as modals from "constants/modal_types";
const { ipcRenderer } = require("electron");
@@ -294,7 +294,7 @@ export function doPurchaseUri(uri, purchaseModalName) {
}
if (cost > balance) {
- dispatch(doOpenModal("notEnoughCredits"));
+ dispatch(doOpenModal(modals.INSUFFICIENT_CREDITS));
} else {
dispatch(doOpenModal(purchaseModalName));
}
diff --git a/ui/js/actions/rewards.js b/ui/js/actions/rewards.js
index 9c5d5143a..95ae3b25b 100644
--- a/ui/js/actions/rewards.js
+++ b/ui/js/actions/rewards.js
@@ -1,4 +1,5 @@
import * as types from "constants/action_types";
+import * as modals from "constants/modal_types";
import lbryio from "lbryio";
import rewards from "rewards";
import { selectRewardsByType } from "selectors/rewards";
@@ -58,6 +59,12 @@ export function doClaimReward(reward, saveError = false) {
reward,
},
});
+ if (reward.reward_type == rewards.TYPE_NEW_USER) {
+ dispatch({
+ type: types.OPEN_MODAL,
+ data: { modal: modals.FIRST_REWARD },
+ });
+ }
};
const failure = error => {
@@ -99,9 +106,7 @@ export function doClaimEligiblePurchaseRewards() {
if (unclaimedType) {
dispatch(doClaimRewardType(unclaimedType));
}
- if (types[rewards.TYPE_FEATURED_DOWNLOAD] === false) {
- dispatch(doClaimRewardType(rewards.TYPE_FEATURED_DOWNLOAD));
- }
+ dispatch(doClaimRewardType(rewards.TYPE_FEATURED_DOWNLOAD));
};
}
diff --git a/ui/js/actions/user.js b/ui/js/actions/user.js
index a2db27c9f..e2fa9b917 100644
--- a/ui/js/actions/user.js
+++ b/ui/js/actions/user.js
@@ -1,8 +1,9 @@
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";
+import { doRewardList, doClaimRewardType } from "actions/rewards";
+import { selectEmailToVerify, selectUser } from "selectors/user";
+import rewards from "rewards";
export function doAuthenticate() {
return function(dispatch, getState) {
@@ -137,6 +138,37 @@ export function doUserEmailVerify(verificationToken) {
};
}
+export function doUserIdentityVerify(stripeToken) {
+ return function(dispatch, getState) {
+ dispatch({
+ type: types.USER_IDENTITY_VERIFY_STARTED,
+ token: stripeToken,
+ });
+
+ lbryio
+ .call("user", "verify_identity", { stripe_token: stripeToken }, "post")
+ .then(user => {
+ if (user.is_identity_verified) {
+ dispatch({
+ type: types.USER_IDENTITY_VERIFY_SUCCESS,
+ data: { user },
+ });
+ dispatch(doClaimRewardType(rewards.TYPE_NEW_USER));
+ } else {
+ throw new Error(
+ "Your identity is still not verified. This should not happen."
+ ); //shouldn't happen
+ }
+ })
+ .catch(error => {
+ dispatch({
+ type: types.USER_IDENTITY_VERIFY_FAILURE,
+ data: { error: error.toString() },
+ });
+ });
+ };
+}
+
export function doFetchAccessToken() {
return function(dispatch, getState) {
const success = token =>
diff --git a/ui/js/component/app/index.js b/ui/js/component/app/index.js
index 3749741bb..ff4940f88 100644
--- a/ui/js/component/app/index.js
+++ b/ui/js/component/app/index.js
@@ -1,23 +1,41 @@
import React from "react";
import { connect } from "react-redux";
-
import { selectCurrentModal } from "selectors/app";
import {
doCheckUpgradeAvailable,
+ doOpenModal,
doAlertError,
doRecordScroll,
- doCheckDaemonVersion,
} 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)),
recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)),
});
diff --git a/ui/js/component/app/view.jsx b/ui/js/component/app/view.jsx
index 857bd7cf6..e364c0db0 100644
--- a/ui/js/component/app/view.jsx
+++ b/ui/js/component/app/view.jsx
@@ -3,30 +3,58 @@ import Router from "component/router";
import Header from "component/header";
import ModalError from "component/modalError";
import ModalDownloading from "component/modalDownloading";
+import ModalInsufficientCredits from "component/modalInsufficientCredits";
import ModalUpgrade from "component/modalUpgrade";
import ModalWelcome from "component/modalWelcome";
+import ModalFirstReward from "component/modalFirstReward";
import lbry from "lbry";
-import { Line } from "rc-progress";
+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);
+
this.scrollListener = () => this.props.recordScroll(window.scrollY);
window.addEventListener("scroll", this.scrollListener);
}
+ componentWillReceiveProps(nextProps) {
+ this.showWelcome(nextProps);
+ }
+
+ showWelcome(props) {
+ const {
+ isFetchingRewards,
+ isWelcomeAcknowledged,
+ isWelcomeRewardClaimed,
+ openWelcomeModal,
+ user,
+ } = props;
+
+ if (
+ !isWelcomeAcknowledged &&
+ user &&
+ (isFetchingRewards === false && isWelcomeRewardClaimed === false)
+ ) {
+ openWelcomeModal();
+ }
+ }
+
componentWillUnmount() {
window.removeEventListener("scroll", this.scrollListener);
}
@@ -40,10 +68,12 @@ class App extends React.PureComponent {
- {modal == "upgrade" && }
- {modal == "downloading" && }
- {modal == "error" && }
- {modal == "welcome" && }
+ {modal == modals.UPGRADE && }
+ {modal == modals.DOWNLOADING && }
+ {modal == modals.ERROR && }
+ {modal == modals.INSUFFICIENT_CREDITS && }
+ {modal == modals.WELCOME && }
+ {modal == modals.FIRST_REWARD && }
);
}
diff --git a/ui/js/component/auth/index.js b/ui/js/component/auth/index.js
deleted file mode 100644
index 37af9f90f..000000000
--- a/ui/js/component/auth/index.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from "react";
-import { connect } from "react-redux";
-import {
- selectAuthenticationIsPending,
- selectEmailToVerify,
- selectUserIsVerificationCandidate,
-} from "selectors/user";
-import Auth from "./view";
-
-const select = state => ({
- isPending: selectAuthenticationIsPending(state),
- email: selectEmailToVerify(state),
- isVerificationCandidate: selectUserIsVerificationCandidate(state),
-});
-
-export default connect(select, null)(Auth);
diff --git a/ui/js/component/auth/view.jsx b/ui/js/component/auth/view.jsx
deleted file mode 100644
index 551113ffa..000000000
--- a/ui/js/component/auth/view.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from "react";
-import { BusyMessage } from "component/common";
-import UserEmailNew from "component/userEmailNew";
-import UserEmailVerify from "component/userEmailVerify";
-
-export class Auth extends React.PureComponent {
- render() {
- const { isPending, email, isVerificationCandidate } = this.props;
-
- if (isPending) {
- return ;
- } else if (!email) {
- return ;
- } else if (isVerificationCandidate) {
- return ;
- } else {
- return {__("No further steps.")} ;
- }
- }
-}
-
-export default Auth;
diff --git a/ui/js/component/authOverlay/index.jsx b/ui/js/component/authOverlay/index.jsx
deleted file mode 100644
index 28b49333c..000000000
--- a/ui/js/component/authOverlay/index.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from "react";
-import * as modal from "constants/modal_types";
-import rewards from "rewards.js";
-import { connect } from "react-redux";
-import { doUserEmailDecline } from "actions/user";
-import { doOpenModal } from "actions/app";
-import {
- selectAuthenticationIsPending,
- selectUserHasEmail,
- selectUserIsAuthRequested,
-} from "selectors/user";
-import { makeSelectHasClaimedReward } from "selectors/rewards";
-import AuthOverlay from "./view";
-
-const select = (state, props) => {
- const selectHasClaimed = makeSelectHasClaimedReward();
-
- return {
- hasEmail: selectUserHasEmail(state),
- isPending: selectAuthenticationIsPending(state),
- isShowing: selectUserIsAuthRequested(state),
- hasNewUserReward: selectHasClaimed(state, {
- reward_type: rewards.TYPE_NEW_USER,
- }),
- };
-};
-
-const perform = dispatch => ({
- userEmailDecline: () => dispatch(doUserEmailDecline()),
- openWelcomeModal: () => dispatch(doOpenModal(modal.WELCOME)),
-});
-
-export default connect(select, perform)(AuthOverlay);
diff --git a/ui/js/component/authOverlay/view.jsx b/ui/js/component/authOverlay/view.jsx
deleted file mode 100644
index 753fe2fe4..000000000
--- a/ui/js/component/authOverlay/view.jsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import React from "react";
-import lbryio from "lbryio.js";
-import ModalPage from "component/modal-page.js";
-import Auth from "component/auth";
-import Link from "component/link";
-import { getLocal, setLocal } from "utils";
-
-export class AuthOverlay extends React.PureComponent {
- constructor(props) {
- super(props);
-
- this.state = {
- showNoEmailConfirm: false,
- };
- }
-
- componentWillReceiveProps(nextProps) {
- if (
- this.props.isShowing &&
- !this.props.isPending &&
- !nextProps.hasNewUserReward &&
- !nextProps.isShowing /* && !getLocal("welcome_screen_shown")*/
- ) {
- setLocal("welcome_screen_shown", true);
- setTimeout(() => this.props.openWelcomeModal(), 1);
- }
- }
-
- onEmailSkipClick() {
- this.setState({ showNoEmailConfirm: true });
- }
-
- onEmailSkipConfirm() {
- this.props.userEmailDecline();
- }
-
- render() {
- if (!lbryio.enabled) {
- return null;
- }
-
- const { isPending, isShowing, hasEmail } = this.props;
-
- if (isShowing) {
- return (
-
- LBRY Early Access
-
- {isPending
- ? ""
- :
- {!hasEmail && this.state.showNoEmailConfirm
- ?
-
- {__(
- "If you continue without an email, you will be ineligible to earn free LBC rewards, as well as unable to receive security related communications."
- )}
-
-
{
- this.onEmailSkipConfirm();
- }}
- label={__("Continue without email")}
- />
-
- :
{
- hasEmail
- ? this.onEmailSkipConfirm()
- : this.onEmailSkipClick();
- }}
- label={
- hasEmail ? __("Skip for now") : __("Do I have to?")
- }
- />}
-
}
-
- );
- }
-
- return null;
- }
-}
-
-export default AuthOverlay;
diff --git a/ui/js/component/cardVerify/index.js b/ui/js/component/cardVerify/index.js
new file mode 100644
index 000000000..32cd22aef
--- /dev/null
+++ b/ui/js/component/cardVerify/index.js
@@ -0,0 +1,12 @@
+import React from "react";
+import { connect } from "react-redux";
+import { selectUserEmail } from "selectors/user";
+import CardVerify from "./view";
+
+const select = state => ({
+ email: selectUserEmail(state),
+});
+
+const perform = dispatch => ({});
+
+export default connect(select, perform)(CardVerify);
diff --git a/ui/js/component/cardVerify/view.jsx b/ui/js/component/cardVerify/view.jsx
new file mode 100644
index 000000000..79d4370a4
--- /dev/null
+++ b/ui/js/component/cardVerify/view.jsx
@@ -0,0 +1,377 @@
+import React from "react";
+import PropTypes from "prop-types";
+import Link from "component/link";
+
+let scriptLoading = false;
+let scriptLoaded = false;
+let scriptDidError = false;
+
+class CardVerify extends React.Component {
+ static defaultProps = {
+ label: "Verify",
+ locale: "auto",
+ };
+
+ static propTypes = {
+ // If included, will render the default blue button with label text.
+ // (Requires including stripe-checkout.css or adding the .styl file
+ // to your pipeline)
+ label: PropTypes.string,
+
+ // =====================================================
+ // Required by stripe
+ // see Stripe docs for more info:
+ // https://stripe.com/docs/checkout#integration-custom
+ // =====================================================
+
+ // Your publishable key (test or live).
+ // can't use "key" as a prop in react, so have to change the keyname
+ stripeKey: PropTypes.string.isRequired,
+
+ // The callback to invoke when the Checkout process is complete.
+ // function(token)
+ // token is the token object created.
+ // token.id can be used to create a charge or customer.
+ // token.email contains the email address entered by the user.
+ token: PropTypes.func.isRequired,
+
+ // ==========================
+ // Highly Recommended Options
+ // ==========================
+
+ // Name of the company or website.
+ name: PropTypes.string,
+
+ // A description of the product or service being purchased.
+ description: PropTypes.string,
+
+ // Specify auto to display Checkout in the user's preferred language, if
+ // available. English will be used by default.
+ //
+ // https://stripe.com/docs/checkout#supported-languages
+ // for more info.
+ locale: PropTypes.oneOf([
+ "auto", // (Default) Automatically chosen by checkout
+ "zh", // Simplified Chinese
+ "da", // Danish
+ "nl", // Dutch
+ "en", // English
+ "fr", // French
+ "de", // German
+ "it", // Italian
+ "ja", // Japanease
+ "no", // Norwegian
+ "es", // Spanish
+ "sv", // Swedish
+ ]),
+
+ // ==============
+ // Optional Props
+ // ==============
+
+ // The currency of the amount (3-letter ISO code). The default is USD.
+ currency: PropTypes.oneOf([
+ "AED",
+ "AFN",
+ "ALL",
+ "AMD",
+ "ANG",
+ "AOA",
+ "ARS",
+ "AUD",
+ "AWG",
+ "AZN",
+ "BAM",
+ "BBD",
+ "BDT",
+ "BGN",
+ "BIF",
+ "BMD",
+ "BND",
+ "BOB",
+ "BRL",
+ "BSD",
+ "BWP",
+ "BZD",
+ "CAD",
+ "CDF",
+ "CHF",
+ "CLP",
+ "CNY",
+ "COP",
+ "CRC",
+ "CVE",
+ "CZK",
+ "DJF",
+ "DKK",
+ "DOP",
+ "DZD",
+ "EEK",
+ "EGP",
+ "ETB",
+ "EUR",
+ "FJD",
+ "FKP",
+ "GBP",
+ "GEL",
+ "GIP",
+ "GMD",
+ "GNF",
+ "GTQ",
+ "GYD",
+ "HKD",
+ "HNL",
+ "HRK",
+ "HTG",
+ "HUF",
+ "IDR",
+ "ILS",
+ "INR",
+ "ISK",
+ "JMD",
+ "JPY",
+ "KES",
+ "KGS",
+ "KHR",
+ "KMF",
+ "KRW",
+ "KYD",
+ "KZT",
+ "LAK",
+ "LBP",
+ "LKR",
+ "LRD",
+ "LSL",
+ "LTL",
+ "LVL",
+ "MAD",
+ "MDL",
+ "MGA",
+ "MKD",
+ "MNT",
+ "MOP",
+ "MRO",
+ "MUR",
+ "MVR",
+ "MWK",
+ "MXN",
+ "MYR",
+ "MZN",
+ "NAD",
+ "NGN",
+ "NIO",
+ "NOK",
+ "NPR",
+ "NZD",
+ "PAB",
+ "PEN",
+ "PGK",
+ "PHP",
+ "PKR",
+ "PLN",
+ "PYG",
+ "QAR",
+ "RON",
+ "RSD",
+ "RUB",
+ "RWF",
+ "SAR",
+ "SBD",
+ "SCR",
+ "SEK",
+ "SGD",
+ "SHP",
+ "SLL",
+ "SOS",
+ "SRD",
+ "STD",
+ "SVC",
+ "SZL",
+ "THB",
+ "TJS",
+ "TOP",
+ "TRY",
+ "TTD",
+ "TWD",
+ "TZS",
+ "UAH",
+ "UGX",
+ "USD",
+ "UYU",
+ "UZS",
+ "VND",
+ "VUV",
+ "WST",
+ "XAF",
+ "XCD",
+ "XOF",
+ "XPF",
+ "YER",
+ "ZAR",
+ "ZMW",
+ ]),
+
+ // The label of the payment button in the Checkout form (e.g. “Subscribe”,
+ // “Pay {{amount}}”, etc.). If you include {{amount}}, it will be replaced
+ // by the provided amount. Otherwise, the amount will be appended to the
+ // end of your label.
+ panelLabel: PropTypes.string,
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ open: false,
+ };
+ }
+
+ componentDidMount() {
+ if (scriptLoaded) {
+ return;
+ }
+
+ if (scriptLoading) {
+ return;
+ }
+
+ scriptLoading = true;
+
+ const script = document.createElement("script");
+ script.src = "https://checkout.stripe.com/checkout.js";
+ script.async = 1;
+
+ this.loadPromise = (() => {
+ let canceled = false;
+ const promise = new Promise((resolve, reject) => {
+ script.onload = () => {
+ scriptLoaded = true;
+ scriptLoading = false;
+ resolve();
+ this.onScriptLoaded();
+ };
+ script.onerror = event => {
+ scriptDidError = true;
+ scriptLoading = false;
+ reject(event);
+ this.onScriptError(event);
+ };
+ });
+ const wrappedPromise = new Promise((accept, cancel) => {
+ promise.then(
+ () => (canceled ? cancel({ isCanceled: true }) : accept())
+ );
+ promise.catch(
+ error => (canceled ? cancel({ isCanceled: true }) : cancel(error))
+ );
+ });
+
+ return {
+ promise: wrappedPromise,
+ cancel() {
+ canceled = true;
+ },
+ };
+ })();
+
+ this.loadPromise.promise
+ .then(this.onScriptLoaded)
+ .catch(this.onScriptError);
+
+ document.body.appendChild(script);
+ }
+
+ componentDidUpdate() {
+ if (!scriptLoading) {
+ this.updateStripeHandler();
+ }
+ }
+
+ componentWillUnmount() {
+ if (this.loadPromise) {
+ this.loadPromise.cancel();
+ }
+ if (CardVerify.stripeHandler && this.state.open) {
+ CardVerify.stripeHandler.close();
+ }
+ }
+
+ onScriptLoaded = () => {
+ if (!CardVerify.stripeHandler) {
+ CardVerify.stripeHandler = StripeCheckout.configure({
+ key: this.props.stripeKey,
+ });
+ if (this.hasPendingClick) {
+ this.showStripeDialog();
+ }
+ }
+ };
+
+ onScriptError = (...args) => {
+ throw new Error("Unable to load credit validation script.");
+ };
+
+ onClosed = () => {
+ this.setState({ open: false });
+ };
+
+ getConfig = () =>
+ ["token", "name", "description"].reduce(
+ (config, key) =>
+ Object.assign(
+ {},
+ config,
+ this.props.hasOwnProperty(key) && {
+ [key]: this.props[key],
+ }
+ ),
+ {
+ allowRememberMe: false,
+ closed: this.onClosed,
+ description: __("Confirm Identity"),
+ email: this.props.email,
+ panelLabel: "Verify",
+ }
+ );
+
+ updateStripeHandler() {
+ if (!CardVerify.stripeHandler) {
+ CardVerify.stripeHandler = StripeCheckout.configure({
+ key: this.props.stripeKey,
+ });
+ }
+ }
+
+ showStripeDialog() {
+ this.setState({ open: true });
+ CardVerify.stripeHandler.open(this.getConfig());
+ }
+
+ onClick = () => {
+ if (scriptDidError) {
+ try {
+ throw new Error(
+ "Tried to call onClick, but StripeCheckout failed to load"
+ );
+ } catch (x) {}
+ } else if (CardVerify.stripeHandler) {
+ this.showStripeDialog();
+ } else {
+ this.hasPendingClick = true;
+ }
+ };
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+export default CardVerify;
diff --git a/ui/js/component/common.js b/ui/js/component/common.js
index 38dbf83fd..8e7279248 100644
--- a/ui/js/component/common.js
+++ b/ui/js/component/common.js
@@ -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 || ""}
/>
);
}
diff --git a/ui/js/component/fileActions/view.jsx b/ui/js/component/fileActions/view.jsx
index ef72463c5..9ff0fbaa1 100644
--- a/ui/js/component/fileActions/view.jsx
+++ b/ui/js/component/fileActions/view.jsx
@@ -181,13 +181,6 @@ class FileActions extends React.PureComponent {
{" "}
{__("credits")}.
-
- {__("You don't have enough LBRY credits to pay for this stream.")}
-
({
- balance: lbry.formatCredits(selectBalance(state), 1),
+ balance: formatCredits(selectBalance(state), 1),
publish: __("Publish"),
});
diff --git a/ui/js/component/link/view.jsx b/ui/js/component/link/view.jsx
index 2f9c7478e..a39e9947c 100644
--- a/ui/js/component/link/view.jsx
+++ b/ui/js/component/link/view.jsx
@@ -11,7 +11,6 @@ const Link = props => {
icon,
badge,
button,
- hidden,
disabled,
children,
} = props;
diff --git a/ui/js/component/modal-page.js b/ui/js/component/modal-page.js
deleted file mode 100644
index f63d120f5..000000000
--- a/ui/js/component/modal-page.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from "react";
-import ReactModal from "react-modal";
-
-export class ModalPage extends React.PureComponent {
- render() {
- return (
-
-
- {this.props.children}
-
-
- );
- }
-}
-
-export default ModalPage;
diff --git a/ui/js/component/modalFirstReward/index.js b/ui/js/component/modalFirstReward/index.js
new file mode 100644
index 000000000..5993a990e
--- /dev/null
+++ b/ui/js/component/modalFirstReward/index.js
@@ -0,0 +1,20 @@
+import React from "react";
+import rewards from "rewards";
+import { connect } from "react-redux";
+import { doCloseModal } from "actions/app";
+import { makeSelectRewardByType } from "selectors/rewards";
+import ModalFirstReward from "./view";
+
+const select = (state, props) => {
+ const selectReward = makeSelectRewardByType();
+
+ return {
+ reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
+ };
+};
+
+const perform = dispatch => ({
+ closeModal: () => dispatch(doCloseModal()),
+});
+
+export default connect(select, perform)(ModalFirstReward);
diff --git a/ui/js/component/modalFirstReward/view.jsx b/ui/js/component/modalFirstReward/view.jsx
new file mode 100644
index 000000000..fc0aead0f
--- /dev/null
+++ b/ui/js/component/modalFirstReward/view.jsx
@@ -0,0 +1,50 @@
+import React from "react";
+import { Modal } from "component/modal";
+import { CreditAmount } from "component/common";
+
+class ModalFirstReward extends React.PureComponent {
+ render() {
+ const { closeModal, reward } = this.props;
+
+ return (
+
+
+ {__("About Your Reward")}
+
+ {__("You earned a reward of")}
+ {" "}
+ {" "}{__("LBRY credits, or")} {__("LBC")} .
+
+
+ {__(
+ "This reward will show in your Wallet momentarily, shown in the top right, probably while you are reading this message."
+ )}
+
+
+ {__(
+ "LBC is used to compensate creators, to publish, and to have say in how the network works."
+ )}
+
+
+ {__(
+ "No need to understand it all just yet! Try watching or downloading something next."
+ )}
+
+
+ {__(
+ "Finally, pleaseh know that LBRY is an early beta and that it earns the name."
+ )}
+
+
+
+ );
+ }
+}
+
+export default ModalFirstReward;
diff --git a/ui/js/component/modalInsufficientCredits/index.js b/ui/js/component/modalInsufficientCredits/index.js
new file mode 100644
index 000000000..0ece4f1fe
--- /dev/null
+++ b/ui/js/component/modalInsufficientCredits/index.js
@@ -0,0 +1,16 @@
+import React from "react";
+import { connect } from "react-redux";
+import { doCloseModal, doNavigate } from "actions/app";
+import ModalInsufficientCredits from "./view";
+
+const select = state => ({});
+
+const perform = dispatch => ({
+ addFunds: () => {
+ dispatch(doNavigate("/rewards"));
+ dispatch(doCloseModal());
+ },
+ closeModal: () => dispatch(doCloseModal()),
+});
+
+export default connect(select, perform)(ModalInsufficientCredits);
diff --git a/ui/js/component/modalInsufficientCredits/view.jsx b/ui/js/component/modalInsufficientCredits/view.jsx
new file mode 100644
index 000000000..fd214cd11
--- /dev/null
+++ b/ui/js/component/modalInsufficientCredits/view.jsx
@@ -0,0 +1,24 @@
+import React from "react";
+import { Modal } from "component/modal";
+
+class ModalInsufficientCredits extends React.PureComponent {
+ render() {
+ const { addFunds, closeModal } = this.props;
+
+ return (
+
+ {__("More LBRY credits are required to purchase this.")}
+
+ );
+ }
+}
+
+export default ModalInsufficientCredits;
diff --git a/ui/js/component/modalUpgrade/view.jsx b/ui/js/component/modalUpgrade/view.jsx
index 544fd96b7..2d364bd31 100644
--- a/ui/js/component/modalUpgrade/view.jsx
+++ b/ui/js/component/modalUpgrade/view.jsx
@@ -1,6 +1,5 @@
import React from "react";
import { Modal } from "component/modal";
-import { downloadUpgrade, skipUpgrade } from "actions/app";
class ModalUpgrade extends React.PureComponent {
render() {
diff --git a/ui/js/component/modalWelcome/index.js b/ui/js/component/modalWelcome/index.js
index 12ec5c0be..4d8962a70 100644
--- a/ui/js/component/modalWelcome/index.js
+++ b/ui/js/component/modalWelcome/index.js
@@ -1,11 +1,11 @@
import React from "react";
import rewards from "rewards";
import { connect } from "react-redux";
-import { doCloseModal } from "actions/app";
+import { doCloseModal, doAuthNavigate } from "actions/app";
+import { doSetClientSetting } from "actions/settings";
import { selectUserIsRewardApproved } from "selectors/user";
import {
makeSelectHasClaimedReward,
- makeSelectClaimRewardError,
makeSelectRewardByType,
} from "selectors/rewards";
import ModalWelcome from "./view";
@@ -15,14 +15,24 @@ const select = (state, props) => {
selectReward = makeSelectRewardByType();
return {
- hasClaimed: selectHasClaimed(state, { reward_type: rewards.TYPE_NEW_USER }),
isRewardApproved: selectUserIsRewardApproved(state),
reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
};
};
-const perform = dispatch => ({
- closeModal: () => dispatch(doCloseModal()),
-});
+const perform = dispatch => () => {
+ const closeModal = () => {
+ dispatch(doSetClientSetting("welcome_acknowledged", true));
+ dispatch(doCloseModal());
+ };
+
+ return {
+ verifyAccount: () => {
+ closeModal();
+ dispatch(doAuthNavigate("/rewards"));
+ },
+ closeModal: closeModal,
+ };
+};
export default connect(select, perform)(ModalWelcome);
diff --git a/ui/js/component/modalWelcome/view.jsx b/ui/js/component/modalWelcome/view.jsx
index 82448c3ae..c87df9da7 100644
--- a/ui/js/component/modalWelcome/view.jsx
+++ b/ui/js/component/modalWelcome/view.jsx
@@ -6,75 +6,45 @@ import RewardLink from "component/rewardLink";
class ModalWelcome extends React.PureComponent {
render() {
- const { closeModal, hasClaimed, isRewardApproved, reward } = this.props;
+ const { closeModal, isRewardApproved, reward, verifyAccount } = this.props;
- return !hasClaimed
- ?
-
- {__("Welcome to LBRY.")}
-
- {__(
- "Using LBRY is like dating a centaur. Totally normal up top, and"
- )}
- {" "}{__("way different")} {__("underneath.")}
-
- {__("Up top, LBRY is similar to popular media sites.")}
-
- {__(
- "Below, LBRY is controlled by users -- you -- via blockchain and decentralization."
- )}
-
-
- {__("Thank you for making content freedom possible!")}
- {" "}{isRewardApproved ? __("Here's a nickel, kid.") : ""}
-
-
- {isRewardApproved
- ?
- : }
-
-
-
- :
-
- {__("About Your Reward")}
-
- {__("You earned a reward of")}
- {" "}
- {" "}{__("LBRY credits, or")} {__("LBC")} .
-
-
- {__(
- "This reward will show in your Wallet momentarily, probably while you are reading this message."
- )}
-
-
- {__(
- "LBC is used to compensate creators, to publish, and to have say in how the network works."
- )}
-
-
- {__(
- "No need to understand it all just yet! Try watching or downloading something next."
- )}
-
-
- {__(
- "Finally, know that LBRY is an early beta and that it earns the name."
- )}
-
-
- ;
+ return (
+
+
+ {__("Welcome to LBRY.")}
+
+ {__(
+ "Using LBRY is like dating a centaur. Totally normal up top, and"
+ )}
+ {" "}{__("way different")} {__("underneath.")}
+
+ {__("Up top, LBRY is similar to popular media sites.")}
+
+ {__(
+ "Below, LBRY is controlled by users -- you -- via blockchain and decentralization."
+ )}
+
+
+ {__("Please have")} {" "}
+ {reward &&
+ }
+ {!reward && {__("??")} }
+ {" "} {__("as a thank you for building content freedom.")}
+
+
+ {isRewardApproved &&
+ }
+ {!isRewardApproved &&
+ }
+
+
+
+
+ );
}
}
diff --git a/ui/js/component/rewardLink/index.js b/ui/js/component/rewardLink/index.js
index 81b01488b..cf53b2367 100644
--- a/ui/js/component/rewardLink/index.js
+++ b/ui/js/component/rewardLink/index.js
@@ -1,7 +1,6 @@
import React from "react";
import { connect } from "react-redux";
import {
- makeSelectHasClaimedReward,
makeSelectClaimRewardError,
makeSelectRewardByType,
makeSelectIsRewardClaimPending,
@@ -11,13 +10,11 @@ import { doClaimReward, doClaimRewardClearError } from "actions/rewards";
import RewardLink from "./view";
const makeSelect = () => {
- const selectHasClaimedReward = makeSelectHasClaimedReward();
const selectIsPending = makeSelectIsRewardClaimPending();
const selectReward = makeSelectRewardByType();
const selectError = makeSelectClaimRewardError();
const select = (state, props) => ({
- isClaimed: selectHasClaimedReward(state, props),
errorMessage: selectError(state, props),
isPending: selectIsPending(state, props),
reward: selectReward(state, props),
diff --git a/ui/js/component/rewardLink/view.jsx b/ui/js/component/rewardLink/view.jsx
index be3a72f35..36a504d3e 100644
--- a/ui/js/component/rewardLink/view.jsx
+++ b/ui/js/component/rewardLink/view.jsx
@@ -1,5 +1,4 @@
import React from "react";
-import { Icon } from "component/common";
import Modal from "component/modal";
import Link from "component/link";
@@ -10,22 +9,19 @@ const RewardLink = props => {
claimReward,
clearError,
errorMessage,
- isClaimed,
isPending,
} = props;
return (
- {isClaimed
- ?
Reward claimed.
- :
{
- claimReward(reward);
- }}
- />}
+
{
+ claimReward(reward);
+ }}
+ />
{errorMessage
?
{
const component = routesMap[page];
@@ -24,22 +25,23 @@ const Router = props => {
const { currentPage, params } = props;
return route(currentPage, {
- settings: ,
- help: ,
- report: ,
- downloaded: ,
- published: ,
- start: ,
- wallet: ,
- send: ,
- receive: ,
- show: ,
+ auth: ,
channel: ,
- publish: ,
developer: ,
discover: ,
+ downloaded: ,
+ help: ,
+ publish: ,
+ published: ,
+ receive: ,
+ report: ,
rewards: ,
search: ,
+ send: ,
+ settings: ,
+ show: ,
+ start: ,
+ wallet: ,
});
};
diff --git a/ui/js/component/userEmailNew/index.jsx b/ui/js/component/userEmailNew/index.js
similarity index 100%
rename from ui/js/component/userEmailNew/index.jsx
rename to ui/js/component/userEmailNew/index.js
diff --git a/ui/js/component/userEmailNew/view.jsx b/ui/js/component/userEmailNew/view.jsx
index 5391bdb3f..cc553f63e 100644
--- a/ui/js/component/userEmailNew/view.jsx
+++ b/ui/js/component/userEmailNew/view.jsx
@@ -27,7 +27,6 @@ class UserEmailNew extends React.PureComponent {
return (