517 lines
13 KiB
JavaScript
517 lines
13 KiB
JavaScript
import React from "react";
|
|
import lbry from "../lbry.js";
|
|
import lbryio from "../lbryio.js";
|
|
import Modal from "./modal.js";
|
|
import ModalPage from "./modal-page.js";
|
|
import Link from "component/link";
|
|
import { RewardLink } from "component/reward-link";
|
|
import { FormRow } from "../component/form.js";
|
|
import { CreditAmount, Address } from "../component/common.js";
|
|
import { getLocal, setLocal } from "../utils.js";
|
|
|
|
class SubmitEmailStage extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
rewardType: null,
|
|
email: '',
|
|
showNoEmailConfirm: false,
|
|
submitting: false
|
|
};
|
|
}
|
|
|
|
handleEmailChanged(event) {
|
|
this.setState({
|
|
email: event.target.value,
|
|
});
|
|
}
|
|
|
|
onEmailSaved(email) {
|
|
this.props.setStage("confirm", { email: email });
|
|
}
|
|
|
|
onEmailSkipClick() {
|
|
this.setState({ showNoEmailConfirm: true })
|
|
}
|
|
|
|
onEmailSkipConfirm() {
|
|
setLocal('auth_bypassed', true);
|
|
this.props.setStage(null)
|
|
}
|
|
|
|
handleSubmit(event) {
|
|
event.preventDefault();
|
|
|
|
this.setState({
|
|
submitting: true,
|
|
});
|
|
lbryio.call("user_email", "new", { email: this.state.email }, "post").then(
|
|
() => {
|
|
this.onEmailSaved(this.state.email);
|
|
},
|
|
error => {
|
|
if (
|
|
error.xhr &&
|
|
(error.xhr.status == 409 ||
|
|
error.message == __("This email is already in use"))
|
|
) {
|
|
this.onEmailSaved(this.state.email);
|
|
return;
|
|
} else if (this._emailRow) {
|
|
this._emailRow.showError(error.message);
|
|
}
|
|
this.setState({ submitting: false });
|
|
}
|
|
);
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<section>
|
|
<form onSubmit={(event) => { this.handleSubmit(event) }}>
|
|
<FormRow ref={(ref) => { this._emailRow = ref }} type="text" label={__("Email")} placeholder="scrwvwls@lbry.io"
|
|
name="email" value={this.state.email}
|
|
onChange={(event) => { this.handleEmailChanged(event) }} />
|
|
<div className="form-row-submit form-row-submit--with-footer">
|
|
<Link button="primary" label={__("Next")} disabled={this.state.submitting} onClick={(event) => { this.handleSubmit(event) }} />
|
|
</div>
|
|
{ this.state.showNoEmailConfirm ?
|
|
<div>
|
|
<p className="help form-input-width">If you continue without an email, you will be ineligible to earn free LBC rewards, as well as unable to receive security related communications.</p>
|
|
<Link className="button-text-help" onClick={ () => { this.onEmailSkipConfirm() }} label="Continue without email" />
|
|
</div>
|
|
:
|
|
<Link className="button-text-help" onClick={ () => { this.onEmailSkipClick() }} label="Do I have to?" />
|
|
}
|
|
</form>
|
|
</section>
|
|
);
|
|
}
|
|
}
|
|
|
|
class ConfirmEmailStage extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
rewardType: null,
|
|
code: "",
|
|
submitting: false,
|
|
errorMessage: null,
|
|
};
|
|
}
|
|
|
|
handleCodeChanged(event) {
|
|
this.setState({
|
|
code: event.target.value,
|
|
});
|
|
}
|
|
|
|
handleSubmit(event) {
|
|
event.preventDefault();
|
|
this.setState({
|
|
submitting: true,
|
|
});
|
|
|
|
const onSubmitError = error => {
|
|
if (this._codeRow) {
|
|
this._codeRow.showError(error.message);
|
|
}
|
|
this.setState({ submitting: false });
|
|
};
|
|
|
|
lbryio
|
|
.call(
|
|
"user_email",
|
|
"confirm",
|
|
{ verification_token: this.state.code, email: this.props.email },
|
|
"post"
|
|
)
|
|
.then(userEmail => {
|
|
if (userEmail.is_verified) {
|
|
this.props.setStage("welcome");
|
|
} else {
|
|
onSubmitError(new Error(__("Your email is still not verified."))); //shouldn't happen?
|
|
}
|
|
}, onSubmitError);
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<section>
|
|
<form
|
|
onSubmit={event => {
|
|
this.handleSubmit(event);
|
|
}}
|
|
>
|
|
<FormRow
|
|
label={__("Verification Code")}
|
|
ref={ref => {
|
|
this._codeRow = ref;
|
|
}}
|
|
type="text"
|
|
name="code"
|
|
placeholder="a94bXXXXXXXXXXXXXX"
|
|
value={this.state.code}
|
|
onChange={event => {
|
|
this.handleCodeChanged(event);
|
|
}}
|
|
helper={__(
|
|
"A verification code is required to access this version."
|
|
)}
|
|
/>
|
|
<div className="form-row-submit form-row-submit--with-footer">
|
|
<Link
|
|
button="primary"
|
|
label={__("Verify")}
|
|
disabled={this.state.submitting}
|
|
onClick={event => {
|
|
this.handleSubmit(event);
|
|
}}
|
|
/>
|
|
</div>
|
|
<div className="form-field__helper">
|
|
{__("No code?")}
|
|
{" "}
|
|
<Link
|
|
onClick={() => {
|
|
this.props.setStage("nocode");
|
|
}}
|
|
label={__("Click here")}
|
|
/>.
|
|
</div>
|
|
</form>
|
|
</section>
|
|
);
|
|
}
|
|
}
|
|
|
|
class WelcomeStage extends React.Component {
|
|
static propTypes = {
|
|
endAuth: React.PropTypes.func,
|
|
};
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
hasReward: true,
|
|
rewardAmount: null,
|
|
};
|
|
}
|
|
|
|
onRewardClaim(reward) {
|
|
this.setState({
|
|
hasReward: true,
|
|
rewardAmount: reward.amount,
|
|
});
|
|
}
|
|
|
|
render() {
|
|
const {
|
|
claimedRewardsByType,
|
|
fetchingRewards,
|
|
newUserReward,
|
|
} = this.props
|
|
|
|
const hasReward = claimedRewardsByType.length > 0
|
|
|
|
if (fetchingRewards) return null
|
|
if (!newUserReward) return null
|
|
|
|
return !hasReward
|
|
? <Modal
|
|
type="custom"
|
|
isOpen={true}
|
|
contentLabel={__("Welcome to LBRY")}
|
|
{...this.props}
|
|
>
|
|
<section>
|
|
<h3 className="modal__header">{__("Welcome to LBRY.")}</h3>
|
|
<p>
|
|
{__(
|
|
"Using LBRY is like dating a centaur. Totally normal up top, and way different underneath."
|
|
)}
|
|
</p>
|
|
<p>{__("Up top, LBRY is similar to popular media sites.")}</p>
|
|
<p>
|
|
{__(
|
|
"Below, LBRY is controlled by users -- you -- via blockchain and decentralization."
|
|
)}
|
|
</p>
|
|
<p>
|
|
{__(
|
|
"Thank you for making content freedom possible! Here's a nickel, kid."
|
|
)}
|
|
</p>
|
|
<div style={{ textAlign: "center", marginBottom: "12px" }}>
|
|
<RewardLink
|
|
type="new_user"
|
|
button="primary"
|
|
onRewardClaim={event => {
|
|
this.onRewardClaim(event);
|
|
}}
|
|
onRewardFailure={() => this.props.setStage(null)}
|
|
onConfirmed={() => {
|
|
this.props.setStage(null);
|
|
}}
|
|
/>
|
|
</div>
|
|
</section>
|
|
</Modal>
|
|
: <Modal
|
|
type="alert"
|
|
overlayClassName="modal-overlay modal-overlay--clear"
|
|
isOpen={true}
|
|
contentLabel={__("Welcome to LBRY")}
|
|
{...this.props}
|
|
onConfirmed={() => {
|
|
this.props.setStage(null);
|
|
}}
|
|
>
|
|
<section>
|
|
<h3 className="modal__header">{__("About Your Reward")}</h3>
|
|
<p>
|
|
{__("You earned a reward of ")}
|
|
{" "}
|
|
<CreditAmount amount={this.state.rewardAmount} label={false} />
|
|
{" "}{__('LBRY credits, or "LBC".')}
|
|
</p>
|
|
<p>
|
|
{__(
|
|
"This reward will show in your Wallet momentarily, probably while you are reading this message."
|
|
)}
|
|
</p>
|
|
<p>
|
|
{__(
|
|
"LBC is used to compensate creators, to publish, and to have say in how the network works."
|
|
)}
|
|
</p>
|
|
<p>
|
|
{__(
|
|
"No need to understand it all just yet! Try watching or downloading something next."
|
|
)}
|
|
</p>
|
|
<p>
|
|
{__(
|
|
"Finally, know that LBRY is an early beta and that it earns the name."
|
|
)}
|
|
</p>
|
|
</section>
|
|
</Modal>;
|
|
}
|
|
}
|
|
|
|
const ErrorStage = props => {
|
|
return (
|
|
<section>
|
|
<p>{__("An error was encountered that we cannot continue from.")}</p>
|
|
<p>{__("At least we're earning the name beta.")}</p>
|
|
{props.errorText ? <p>{__("Message:")} {props.errorText}</p> : ""}
|
|
<Link
|
|
button="alt"
|
|
label={__("Try Reload")}
|
|
onClick={() => {
|
|
window.location.reload();
|
|
}}
|
|
/>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
const PendingStage = props => {
|
|
return (
|
|
<section>
|
|
<p>
|
|
{__("Preparing for first access")} <span className="busy-indicator" />
|
|
</p>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
class CodeRequiredStage extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this._balanceSubscribeId = null;
|
|
|
|
this.state = {
|
|
balance: 0,
|
|
address: getLocal("wallet_address"),
|
|
};
|
|
}
|
|
|
|
componentWillMount() {
|
|
this._balanceSubscribeId = lbry.balanceSubscribe(balance => {
|
|
this.setState({
|
|
balance: balance,
|
|
});
|
|
});
|
|
|
|
if (!this.state.address) {
|
|
lbry.wallet_unused_address().then(address => {
|
|
setLocal("wallet_address", address);
|
|
this.setState({ address: address });
|
|
});
|
|
}
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
if (this._balanceSubscribeId) {
|
|
lbry.balanceUnsubscribe(this._balanceSubscribeId);
|
|
}
|
|
}
|
|
|
|
render() {
|
|
const disabled = this.state.balance < 1;
|
|
return (
|
|
<div>
|
|
<section className="section-spaced">
|
|
<p>
|
|
{__(
|
|
"Early access to LBRY is restricted as we build and scale the network."
|
|
)}
|
|
</p>
|
|
<p>{__("There are two ways in:")}</p>
|
|
<h3>{__("Own LBRY Credits")}</h3>
|
|
<p>{__("If you own at least 1 LBC, you can get in right now.")}</p>
|
|
<p style={{ textAlign: "center" }}>
|
|
<Link
|
|
onClick={() => {
|
|
setLocal("auth_bypassed", true);
|
|
this.props.setStage(null);
|
|
}}
|
|
disabled={disabled}
|
|
label={__("Let Me In")}
|
|
button={disabled ? "alt" : "primary"}
|
|
/>
|
|
</p>
|
|
<p>
|
|
{__("Your balance is ")}<CreditAmount
|
|
amount={this.state.balance}
|
|
/>. {__("To increase your balance, send credits to this address:")}
|
|
</p>
|
|
<p>
|
|
<Address
|
|
address={
|
|
this.state.address
|
|
? this.state.address
|
|
: __("Generating Address...")
|
|
}
|
|
/>
|
|
</p>
|
|
<p>{__("If you don't understand how to send credits, then...")}</p>
|
|
</section>
|
|
<section>
|
|
<h3>{__("Wait For A Code")}</h3>
|
|
<p>
|
|
{__(
|
|
"If you provide your email, you'll automatically receive a notification when the system is open."
|
|
)}
|
|
</p>
|
|
<p>
|
|
<Link
|
|
onClick={() => {
|
|
this.props.setStage("email");
|
|
}}
|
|
label={__("Return")}
|
|
/>
|
|
</p>
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
export class AuthOverlay extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this._stages = {
|
|
pending: PendingStage,
|
|
error: ErrorStage,
|
|
nocode: CodeRequiredStage,
|
|
email: SubmitEmailStage,
|
|
confirm: ConfirmEmailStage,
|
|
welcome: WelcomeStage,
|
|
};
|
|
|
|
this.state = {
|
|
stage: "pending",
|
|
stageProps: {},
|
|
};
|
|
}
|
|
|
|
setStage(stage, stageProps = {}) {
|
|
this.setState({
|
|
stage: stage,
|
|
stageProps: stageProps,
|
|
});
|
|
}
|
|
|
|
componentWillMount() {
|
|
lbryio
|
|
.authenticate()
|
|
.then(user => {
|
|
if (!user.has_verified_email) {
|
|
if (getLocal("auth_bypassed")) {
|
|
this.setStage(null);
|
|
} else {
|
|
this.setStage("email", {});
|
|
}
|
|
} else {
|
|
const {
|
|
claimedRewardsByType,
|
|
} = this.props
|
|
claimedRewardsByType[rewards.TYPE_NEW_USER] ? this.setStage(null) : this.setStage("welcome")
|
|
}})
|
|
.catch(err => {
|
|
this.setStage("error", { errorText: err.message });
|
|
document.dispatchEvent(
|
|
new CustomEvent("unhandledError", {
|
|
detail: {
|
|
message: err.message,
|
|
data: err.stack,
|
|
},
|
|
})
|
|
);
|
|
});
|
|
}
|
|
|
|
render() {
|
|
if (!this.state.stage) {
|
|
return null;
|
|
}
|
|
const StageContent = this._stages[this.state.stage];
|
|
|
|
if (!StageContent) {
|
|
return (
|
|
<span className="empty">{__("Unknown authentication step.")}</span>
|
|
);
|
|
}
|
|
|
|
return this.state.stage != "welcome"
|
|
? <ModalPage
|
|
className="modal-page--full"
|
|
isOpen={true}
|
|
contentLabel={__("Authentication")}
|
|
>
|
|
<h1>{__("LBRY Early Access")}</h1>
|
|
<StageContent
|
|
{...this.state.stageProps}
|
|
setStage={(stage, stageProps) => {
|
|
this.setStage(stage, stageProps);
|
|
}}
|
|
/>
|
|
</ModalPage>
|
|
: <StageContent
|
|
setStage={(stage, stageProps) => {
|
|
this.setStage(stage, stageProps);
|
|
}}
|
|
{...this.state.stageProps}
|
|
/>;
|
|
}
|
|
}
|
|
|
|
export default AuthOverlay
|