Merge branch 'es6-classes' into redux

This commit is contained in:
Jeremy Kauffman 2017-05-19 09:18:01 -04:00
commit d6680a7ae5
22 changed files with 726 additions and 563 deletions

View file

@ -9,23 +9,28 @@ import {CreditAmount, Address} from "../component/common.js";
import {getLocal, getSession, setSession, setLocal} from '../utils.js'; import {getLocal, getSession, setSession, setLocal} from '../utils.js';
const SubmitEmailStage = React.createClass({ class SubmitEmailStage extends React.Component {
getInitialState: function() { constructor(props) {
return { super(props);
this.state = {
rewardType: null, rewardType: null,
email: '', email: '',
submitting: false submitting: false
}; };
}, }
handleEmailChanged: function(event) {
handleEmailChanged(event) {
this.setState({ this.setState({
email: event.target.value, email: event.target.value,
}); });
}, }
onEmailSaved: function(email) {
onEmailSaved(email) {
this.props.setStage("confirm", { email: email }) this.props.setStage("confirm", { email: email })
}, }
handleSubmit: function(event) {
handleSubmit(event) {
event.preventDefault(); event.preventDefault();
this.setState({ this.setState({
@ -42,38 +47,43 @@ const SubmitEmailStage = React.createClass({
} }
this.setState({ submitting: false }); this.setState({ submitting: false });
}); });
}, }
render: function() {
render() {
return ( return (
<section> <section>
<form onSubmit={this.handleSubmit}> <form onSubmit={(event) => { this.handleSubmit(event) }}>
<FormRow ref={(ref) => { this._emailRow = ref }} type="text" label="Email" placeholder="scrwvwls@lbry.io" <FormRow ref={(ref) => { this._emailRow = ref }} type="text" label="Email" placeholder="scrwvwls@lbry.io"
name="email" value={this.state.email} name="email" value={this.state.email}
onChange={this.handleEmailChanged} /> onChange={(event) => { this.handleEmailChanged(event) }} />
<div className="form-row-submit"> <div className="form-row-submit">
<Link button="primary" label="Next" disabled={this.state.submitting} onClick={this.handleSubmit} /> <Link button="primary" label="Next" disabled={this.state.submitting} onClick={(event) => { this.handleSubmit(event) }} />
</div> </div>
</form> </form>
</section> </section>
); );
} }
}); }
const ConfirmEmailStage = React.createClass({ class ConfirmEmailStage extends React.Component {
getInitialState: function() { constructor(props) {
return { super(props);
this.state = {
rewardType: null, rewardType: null,
code: '', code: '',
submitting: false, submitting: false,
errorMessage: null, errorMessage: null,
}; };
}, }
handleCodeChanged: function(event) {
handleCodeChanged(event) {
this.setState({ this.setState({
code: event.target.value, code: event.target.value,
}); });
}, }
handleSubmit: function(event) {
handleSubmit(event) {
event.preventDefault(); event.preventDefault();
this.setState({ this.setState({
submitting: true, submitting: true,
@ -93,16 +103,17 @@ const ConfirmEmailStage = React.createClass({
onSubmitError(new Error("Your email is still not verified.")) //shouldn't happen? onSubmitError(new Error("Your email is still not verified.")) //shouldn't happen?
} }
}, onSubmitError); }, onSubmitError);
}, }
render: function() {
render() {
return ( return (
<section> <section>
<form onSubmit={this.handleSubmit}> <form onSubmit={(event) => { this.handleSubmit(event) }}>
<FormRow label="Verification Code" ref={(ref) => { this._codeRow = ref }} type="text" <FormRow label="Verification Code" ref={(ref) => { this._codeRow = ref }} type="text"
name="code" placeholder="a94bXXXXXXXXXXXXXX" value={this.state.code} onChange={this.handleCodeChanged} name="code" placeholder="a94bXXXXXXXXXXXXXX" value={this.state.code} onChange={(event) => { this.handleCodeChanged(event) }}
helper="A verification code is required to access this version."/> helper="A verification code is required to access this version."/>
<div className="form-row-submit form-row-submit--with-footer"> <div className="form-row-submit form-row-submit--with-footer">
<Link button="primary" label="Verify" disabled={this.state.submitting} onClick={this.handleSubmit} /> <Link button="primary" label="Verify" disabled={this.state.submitting} onClick={(event) => { this.handleSubmit(event)}} />
</div> </div>
<div className="form-field__helper"> <div className="form-field__helper">
No code? <Link onClick={() => { this.props.setStage("nocode")}} label="Click here" />. No code? <Link onClick={() => { this.props.setStage("nocode")}} label="Click here" />.
@ -111,25 +122,26 @@ const ConfirmEmailStage = React.createClass({
</section> </section>
); );
} }
}); }
const WelcomeStage = React.createClass({ class WelcomeStage extends React.Component {
propTypes: { constructor(props) {
endAuth: React.PropTypes.func, super(props);
},
getInitialState: function() { this.state = {
return {
hasReward: false, hasReward: false,
rewardAmount: null, rewardAmount: null,
} };
}, }
onRewardClaim: function(reward) {
onRewardClaim(reward) {
this.setState({ this.setState({
hasReward: true, hasReward: true,
rewardAmount: reward.amount rewardAmount: reward.amount
}) })
}, }
render: function() {
render() {
return ( return (
!this.state.hasReward ? !this.state.hasReward ?
<Modal type="custom" isOpen={true} contentLabel="Welcome to LBRY" {...this.props}> <Modal type="custom" isOpen={true} contentLabel="Welcome to LBRY" {...this.props}>
@ -140,7 +152,7 @@ const WelcomeStage = React.createClass({
<p>Below, LBRY is controlled by users -- you -- via blockchain and decentralization.</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> <p>Thank you for making content freedom possible! Here's a nickel, kid.</p>
<div style={{textAlign: "center", marginBottom: "12px"}}> <div style={{textAlign: "center", marginBottom: "12px"}}>
<RewardLink type="new_user" button="primary" onRewardClaim={this.onRewardClaim} onRewardFailure={() => this.props.setStage(null)} onConfirmed={() => { this.props.setStage(null) }} /> <RewardLink type="new_user" button="primary" onRewardClaim={(event) => { this.onRewardClaim(event) }} onRewardFailure={() => this.props.setStage(null)} onConfirmed={() => { this.props.setStage(null) }} />
</div> </div>
</section> </section>
</Modal> : </Modal> :
@ -156,11 +168,13 @@ const WelcomeStage = React.createClass({
</Modal> </Modal>
); );
} }
}); }
WelcomeStage.propTypes = {
endAuth: React.PropTypes.func,
};
class ErrorStage extends React.Component {
const ErrorStage = React.createClass({ render() {
render: function() {
return ( return (
<section> <section>
<p>An error was encountered that we cannot continue from.</p> <p>An error was encountered that we cannot continue from.</p>
@ -170,29 +184,32 @@ const ErrorStage = React.createClass({
</section> </section>
); );
} }
}); }
const PendingStage = React.createClass({ class PendingStage extends React.Component {
render: function() { render() {
return ( return (
<section> <section>
<p>Preparing for first access <span className="busy-indicator"></span></p> <p>Preparing for first access <span className="busy-indicator"></span></p>
</section> </section>
); );
} }
}); }
const CodeRequiredStage = React.createClass({ class CodeRequiredStage extends React.Component {
_balanceSubscribeId: null, constructor(props) {
getInitialState: function() { super(props);
return {
this._balanceSubscribeId = nullp
this.state = {
balance: 0, balance: 0,
address: getLocal('wallet_address') address: getLocal('wallet_address')
} };
}, }
componentWillMount: function() { componentWillMount() {
this._balanceSubscribeId = lbry.balanceSubscribe((balance) => { this._balanceSubscribeId = lbry.balanceSubscribe((balance) => {
this.setState({ this.setState({
balance: balance balance: balance
@ -205,13 +222,15 @@ const CodeRequiredStage = React.createClass({
this.setState({ address: address }); this.setState({ address: address });
}); });
} }
}, }
componentWillUnmount: function() {
componentWillUnmount() {
if (this._balanceSubscribeId) { if (this._balanceSubscribeId) {
lbry.balanceUnsubscribe(this._balanceSubscribeId) lbry.balanceUnsubscribe(this._balanceSubscribeId)
} }
}, }
render: function() {
render() {
const disabled = this.state.balance < 1; const disabled = this.state.balance < 1;
return ( return (
<div> <div>
@ -234,31 +253,36 @@ const CodeRequiredStage = React.createClass({
</div> </div>
); );
} }
}); }
export const AuthOverlay = React.createClass({ export class AuthOverlay extends React.Component {
_stages: { constructor(props) {
pending: PendingStage, super(props);
error: ErrorStage,
nocode: CodeRequiredStage, this._stages = {
email: SubmitEmailStage, pending: PendingStage,
confirm: ConfirmEmailStage, error: ErrorStage,
welcome: WelcomeStage nocode: CodeRequiredStage,
}, email: SubmitEmailStage,
getInitialState: function() { confirm: ConfirmEmailStage,
return { welcome: WelcomeStage
}
this.state = {
stage: "pending", stage: "pending",
stageProps: {} stageProps: {}
}; };
}, }
setStage: function(stage, stageProps = {}) {
setStage(stage, stageProps = {}) {
this.setState({ this.setState({
stage: stage, stage: stage,
stageProps: stageProps stageProps: stageProps
}) })
}, }
componentWillMount: function() {
componentWillMount() {
lbryio.authenticate().then((user) => { lbryio.authenticate().then((user) => {
if (!user.HasVerifiedEmail) { if (!user.HasVerifiedEmail) {
if (getLocal('auth_bypassed')) { if (getLocal('auth_bypassed')) {
@ -284,8 +308,9 @@ export const AuthOverlay = React.createClass({
} }
})); }));
}) })
}, }
render: function() {
render() {
if (!this.state.stage) { if (!this.state.stage) {
return null; return null;
} }
@ -294,9 +319,9 @@ export const AuthOverlay = React.createClass({
this.state.stage != "welcome" ? this.state.stage != "welcome" ?
<ModalPage className="modal-page--full" isOpen={true} contentLabel="Authentication" {...this.props}> <ModalPage className="modal-page--full" isOpen={true} contentLabel="Authentication" {...this.props}>
<h1>LBRY Early Access</h1> <h1>LBRY Early Access</h1>
<StageContent {...this.state.stageProps} setStage={this.setStage} /> <StageContent {...this.state.stageProps} setStage={(stage, stageProps) => { this.setStage(stage, stageProps) }} />
</ModalPage> : </ModalPage> :
<StageContent setStage={this.setStage} {...this.state.stageProps} /> <StageContent setStage={(stage, stageProps) => { this.setStage(stage, stageProps) }} {...this.state.stageProps} />
); );
} }
}); }

View file

@ -2,65 +2,69 @@ import React from 'react';
import lbry from '../lbry.js'; import lbry from '../lbry.js';
//component/icon.js //component/icon.js
export let Icon = React.createClass({ export class Icon extends React.Component {
propTypes: { static propTypes = {
icon: React.PropTypes.string.isRequired, icon: React.PropTypes.string.isRequired,
className: React.PropTypes.string, className: React.PropTypes.string,
fixed: React.PropTypes.bool, fixed: React.PropTypes.bool,
}, }
render: function() {
static defaultProps = {
lines: null
}
render() {
const {fixed, className, ...other} = this.props; const {fixed, className, ...other} = this.props;
const spanClassName = ('icon ' + ('fixed' in this.props ? 'icon-fixed-width ' : '') + const spanClassName = ('icon ' + ('fixed' in this.props ? 'icon-fixed-width ' : '') +
this.props.icon + ' ' + (this.props.className || '')); this.props.icon + ' ' + (this.props.className || ''));
return <span className={spanClassName} {... other}></span> return <span className={spanClassName} {... other}></span>
} }
}); }
export let TruncatedText = React.createClass({ export class TruncatedText extends React.Component {
propTypes: { static propTypes = {
lines: React.PropTypes.number lines: React.PropTypes.number,
}, }
getDefaultProps: function() {
return { render() {
lines: null,
}
},
render: function() {
return <span className="truncated-text" style={{ WebkitLineClamp: this.props.lines }}>{this.props.children}</span>; return <span className="truncated-text" style={{ WebkitLineClamp: this.props.lines }}>{this.props.children}</span>;
} }
}); }
export let BusyMessage = React.createClass({ export class BusyMessage extends React.Component {
propTypes: { static propTypes = {
message: React.PropTypes.string message: React.PropTypes.string,
}, }
render: function() {
render() {
return <span>{this.props.message} <span className="busy-indicator"></span></span> return <span>{this.props.message} <span className="busy-indicator"></span></span>
} }
}); }
export let CurrencySymbol = React.createClass({ export class CurrencySymbol extends React.Component {
render: function() { return <span>LBC</span>; } render() {
}); return <span>LBC</span>;
}
}
export let CreditAmount = React.createClass({ export class CreditAmount extends React.Component {
propTypes: { static propTypes = {
amount: React.PropTypes.number.isRequired, amount: React.PropTypes.number.isRequired,
precision: React.PropTypes.number, precision: React.PropTypes.number,
isEstimate: React.PropTypes.bool, isEstimate: React.PropTypes.bool,
label: React.PropTypes.bool, label: React.PropTypes.bool,
showFree: React.PropTypes.bool, showFree: React.PropTypes.bool,
look: React.PropTypes.oneOf(['indicator', 'plain']), look: React.PropTypes.oneOf(['indicator', 'plain']),
}, }
getDefaultProps: function() {
return { static defaultProps = {
precision: 1, precision: 1,
label: true, label: true,
showFree: false, showFree: false,
look: 'indicator', look: 'indicator',
} }
},
render: function() { render() {
const formattedAmount = lbry.formatCredits(this.props.amount, this.props.precision); const formattedAmount = lbry.formatCredits(this.props.amount, this.props.precision);
let amountText; let amountText;
if (this.props.showFree && parseFloat(formattedAmount) == 0) { if (this.props.showFree && parseFloat(formattedAmount) == 0) {
@ -80,45 +84,56 @@ export let CreditAmount = React.createClass({
</span> </span>
); );
} }
}); }
var addressStyle = { let addressStyle = {
fontFamily: '"Consolas", "Lucida Console", "Adobe Source Code Pro", monospace', fontFamily: '"Consolas", "Lucida Console", "Adobe Source Code Pro", monospace',
}; };
export let Address = React.createClass({ export class Address extends React.Component {
_inputElem: null, static propTypes = {
propTypes: {
address: React.PropTypes.string, address: React.PropTypes.string,
}, }
render: function() {
constructor(props) {
super(props);
this._inputElem = null;
}
render() {
return ( return (
<input className="input-copyable" type="text" ref={(input) => { this._inputElem = input; }} <input className="input-copyable" type="text" ref={(input) => { this._inputElem = input; }}
onFocus={() => { this._inputElem.select(); }} style={addressStyle} readOnly="readonly" value={this.props.address}></input> onFocus={() => { this._inputElem.select(); }} style={addressStyle} readOnly="readonly" value={this.props.address}></input>
); );
} }
}); }
export let Thumbnail = React.createClass({ export class Thumbnail extends React.Component {
_defaultImageUri: lbry.imagePath('default-thumb.svg'), static propTypes = {
_maxLoadTime: 10000,
_isMounted: false,
propTypes: {
src: React.PropTypes.string, src: React.PropTypes.string,
}, }
handleError: function() {
handleError() {
if (this.state.imageUrl != this._defaultImageUri) { if (this.state.imageUrl != this._defaultImageUri) {
this.setState({ this.setState({
imageUri: this._defaultImageUri, imageUri: this._defaultImageUri,
}); });
} }
}, }
getInitialState: function() {
return { constructor(props) {
super(props);
this._defaultImageUri = lbry.imagePath('default-thumb.svg')
this._maxLoadTime = 10000
this._isMounted = false
this.state = {
imageUri: this.props.src || this._defaultImageUri, imageUri: this.props.src || this._defaultImageUri,
}; };
}, }
componentDidMount: function() {
componentDidMount() {
this._isMounted = true; this._isMounted = true;
setTimeout(() => { setTimeout(() => {
if (this._isMounted && !this.refs.img.complete) { if (this._isMounted && !this.refs.img.complete) {
@ -127,14 +142,16 @@ export let Thumbnail = React.createClass({
}); });
} }
}, this._maxLoadTime); }, this._maxLoadTime);
}, }
componentWillUnmount: function() {
componentWillUnmount() {
this._isMounted = false; this._isMounted = false;
}, }
render: function() {
render() {
const className = this.props.className ? this.props.className : '', const className = this.props.className ? this.props.className : '',
otherProps = Object.assign({}, this.props) otherProps = Object.assign({}, this.props)
delete otherProps.className; delete otherProps.className;
return <img ref="img" onError={this.handleError} {...otherProps} className={className} src={this.state.imageUri} /> return <img ref="img" onError={() => { this.handleError() }} {...otherProps} className={className} src={this.state.imageUri} />
}, }
}); }

View file

@ -118,7 +118,7 @@ class FileActions extends React.Component {
<DropDownMenuItem key={1} onClick={() => openModal('confirmRemove')} label="Remove..." /> <DropDownMenuItem key={1} onClick={() => openModal('confirmRemove')} label="Remove..." />
</DropDownMenu> : '' } </DropDownMenu> : '' }
<Modal type="confirm" isOpen={modal == 'affirmPurchase'} <Modal type="confirm" isOpen={modal == 'affirmPurchase'}
contentLabel="Confirm Purchase" onConfirmed={this.onAffirmPurchase.bind(this)} onAborted={closeModal}> contentLabel="Confirm Purchase" onConfirmed={this.onAffirmPurchase.bind(this)} onAborted={this.closeModal.bind(this)}>
This will purchase <strong>{title}</strong> for <strong><FilePrice uri={uri} look="plain" /></strong> credits. This will purchase <strong>{title}</strong> for <strong><FilePrice uri={uri} look="plain" /></strong> credits.
</Modal> </Modal>
<Modal isOpen={modal == 'notEnoughCredits'} contentLabel="Not enough credits" <Modal isOpen={modal == 'notEnoughCredits'} contentLabel="Not enough credits"

View file

@ -10,33 +10,29 @@ function formFieldId() {
return "form-field-" + (++formFieldCounter); return "form-field-" + (++formFieldCounter);
} }
export let FormField = React.createClass({ export class FormField extends React.Component {
_fieldRequiredText: 'This field is required', static propTypes = {
_type: null,
_element: null,
propTypes: {
type: React.PropTypes.string.isRequired, type: React.PropTypes.string.isRequired,
prefix: React.PropTypes.string, prefix: React.PropTypes.string,
postfix: React.PropTypes.string, postfix: React.PropTypes.string,
hasError: React.PropTypes.bool hasError: React.PropTypes.bool
}, }
handleFileChosen: function(path) {
this.refs.field.value = path; constructor(props) {
if (this.props.onChange) { // Updating inputs programmatically doesn't generate an event, so we have to make our own super(props);
const event = new Event('change', {bubbles: true})
this.refs.field.dispatchEvent(event); // This alone won't generate a React event, but we use it to attach the field as a target this._fieldRequiredText = 'This field is required';
this.props.onChange(event); this._type = null;
} this._element = null;
},
getInitialState: function() { this.state = {
return {
isError: null, isError: null,
errorMessage: null, errorMessage: null,
} };
}, }
componentWillMount: function() {
if (['text', 'number', 'radio', 'checkbox'].includes(this.props.type)) { componentWillMount() {
if (['text', 'number', 'radio', 'checkbox', 'file'].includes(this.props.type)) {
this._element = 'input'; this._element = 'input';
this._type = this.props.type; this._type = this.props.type;
} else if (this.props.type == 'text-number') { } else if (this.props.type == 'text-number') {
@ -49,8 +45,9 @@ export let FormField = React.createClass({
// Non <input> field, e.g. <select>, <textarea> // Non <input> field, e.g. <select>, <textarea>
this._element = this.props.type; this._element = this.props.type;
} }
}, }
componentDidMount: function() {
componentDidMount() {
/** /**
* We have to add the webkitdirectory attribute here because React doesn't allow it in JSX * We have to add the webkitdirectory attribute here because React doesn't allow it in JSX
* https://github.com/facebook/react/issues/3468 * https://github.com/facebook/react/issues/3468
@ -58,27 +55,41 @@ export let FormField = React.createClass({
if (this.props.type == 'directory') { if (this.props.type == 'directory') {
this.refs.field.webkitdirectory = true; this.refs.field.webkitdirectory = true;
} }
}, }
showError: function(text) {
handleFileChosen(path) {
this.refs.field.value = path;
if (this.props.onChange) { // Updating inputs programmatically doesn't generate an event, so we have to make our own
const event = new Event('change', {bubbles: true})
this.refs.field.dispatchEvent(event); // This alone won't generate a React event, but we use it to attach the field as a target
this.props.onChange(event);
}
}
showError(text) {
this.setState({ this.setState({
isError: true, isError: true,
errorMessage: text, errorMessage: text,
}); });
}, }
focus: function() {
focus() {
this.refs.field.focus(); this.refs.field.focus();
}, }
getValue: function() {
getValue() {
if (this.props.type == 'checkbox') { if (this.props.type == 'checkbox') {
return this.refs.field.checked; return this.refs.field.checked;
} else { } else {
return this.refs.field.value; return this.refs.field.value;
} }
}, }
getSelectedElement: function() {
getSelectedElement() {
return this.refs.field.options[this.refs.field.selectedIndex]; return this.refs.field.options[this.refs.field.selectedIndex];
}, }
render: function() {
render() {
// Pass all unhandled props to the field element // Pass all unhandled props to the field element
const otherProps = Object.assign({}, this.props), const otherProps = Object.assign({}, this.props),
isError = this.state.isError !== null ? this.state.isError : this.props.hasError, isError = this.state.isError !== null ? this.state.isError : this.props.hasError,
@ -114,45 +125,56 @@ export let FormField = React.createClass({
{ isError && this.state.errorMessage ? <div className="form-field__error">{this.state.errorMessage}</div> : '' } { isError && this.state.errorMessage ? <div className="form-field__error">{this.state.errorMessage}</div> : '' }
</div> </div>
} }
}) }
export let FormRow = React.createClass({ export class FormRow extends React.Component {
_fieldRequiredText: 'This field is required', static propTypes = {
propTypes: { label: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.element]),
label: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.element])
// helper: React.PropTypes.html, // helper: React.PropTypes.html,
}, }
getInitialState: function() {
return { constructor(props) {
super(props);
this._fieldRequiredText = 'This field is required';
this.state = {
isError: false, isError: false,
errorMessage: null, errorMessage: null,
} };
}, }
showError: function(text) {
showError(text) {
this.setState({ this.setState({
isError: true, isError: true,
errorMessage: text, errorMessage: text,
}); });
}, }
showRequiredError: function() {
showRequiredError() {
this.showError(this._fieldRequiredText); this.showError(this._fieldRequiredText);
}, }
clearError: function(text) {
clearError(text) {
this.setState({ this.setState({
isError: false, isError: false,
errorMessage: '' errorMessage: ''
}); });
}, }
getValue: function() {
getValue() {
return this.refs.field.getValue(); return this.refs.field.getValue();
}, }
getSelectedElement: function() {
getSelectedElement() {
return this.refs.field.getSelectedElement(); return this.refs.field.getSelectedElement();
}, }
focus: function() {
focus() {
this.refs.field.focus(); this.refs.field.focus();
}, }
render: function() {
render() {
const fieldProps = Object.assign({}, this.props), const fieldProps = Object.assign({}, this.props),
elementId = formFieldId(), elementId = formFieldId(),
renderLabelInFormField = formFieldNestedLabelTypes.includes(this.props.type); renderLabelInFormField = formFieldNestedLabelTypes.includes(this.props.type);
@ -174,4 +196,4 @@ export let FormRow = React.createClass({
{ this.state.isError ? <div className="form-field__error">{this.state.errorMessage}</div> : '' } { this.state.isError ? <div className="form-field__error">{this.state.errorMessage}</div> : '' }
</div> </div>
} }
}) }

View file

@ -92,7 +92,7 @@ export default Link
// return ( // return (
// <a className={className} href={this.props.href || 'javascript:;'} title={this.props.title} // <a className={className} href={this.props.href || 'javascript:;'} title={this.props.title}
// onClick={this.handleClick} {... 'style' in this.props ? {style: this.props.style} : {}}> // onClick={(event) => { this.handleClick() }} {... 'style' in this.props ? {style: this.props.style} : {}}>
// {content} // {content}
// </a> // </a>
// ); // );

View file

@ -3,25 +3,28 @@ import lbry from '../lbry.js';
import {BusyMessage, Icon} from './common.js'; import {BusyMessage, Icon} from './common.js';
import Link from 'component/link' import Link from 'component/link'
var LoadScreen = React.createClass({ class LoadScreen extends React.Component {
propTypes: { static propTypes = {
message: React.PropTypes.string.isRequired, message: React.PropTypes.string.isRequired,
details: React.PropTypes.string, details: React.PropTypes.string,
isWarning: React.PropTypes.bool, isWarning: React.PropTypes.bool,
}, }
getDefaultProps: function() {
return { constructor(props) {
isWarning: false, super(props);
}
}, this.state = {
getInitialState: function() {
return {
message: null, message: null,
details: null, details: null,
isLagging: false, isLagging: false,
} };
}, }
render: function() {
static defaultProps = {
isWarning: false,
}
render() {
const imgSrc = lbry.imagePath('lbry-white-485x160.png'); const imgSrc = lbry.imagePath('lbry-white-485x160.png');
return ( return (
<div className="load-screen"> <div className="load-screen">
@ -35,7 +38,7 @@ var LoadScreen = React.createClass({
</div> </div>
); );
} }
}); }
export default LoadScreen; export default LoadScreen;

View file

@ -2,19 +2,19 @@ import React from 'react';
import {Icon} from './common.js'; import {Icon} from './common.js';
import Link from 'component/link'; import Link from 'component/link';
export let DropDownMenuItem = React.createClass({ export class DropDownMenuItem extends React.Component {
propTypes: { static propTypes = {
href: React.PropTypes.string, href: React.PropTypes.string,
label: React.PropTypes.string, label: React.PropTypes.string,
icon: React.PropTypes.string, icon: React.PropTypes.string,
onClick: React.PropTypes.func, onClick: React.PropTypes.func,
}, }
getDefaultProps: function() {
return { static defaultProps = {
iconPosition: 'left', iconPosition: 'left',
} }
},
render: function() { render() {
var icon = (this.props.icon ? <Icon icon={this.props.icon} fixed /> : null); var icon = (this.props.icon ? <Icon icon={this.props.icon} fixed /> : null);
return ( return (
@ -26,23 +26,27 @@ export let DropDownMenuItem = React.createClass({
</a> </a>
); );
} }
}); }
export let DropDownMenu = React.createClass({ export class DropDownMenu extends React.Component {
_isWindowClickBound: false, constructor(props) {
_menuDiv: null, super(props);
getInitialState: function() { this._isWindowClickBound = false;
return { this._menuDiv = null;
this.state = {
menuOpen: false, menuOpen: false,
}; };
}, }
componentWillUnmount: function() {
componentWillUnmount() {
if (this._isWindowClickBound) { if (this._isWindowClickBound) {
window.removeEventListener('click', this.handleWindowClick, false); window.removeEventListener('click', this.handleWindowClick, false);
} }
}, }
handleMenuIconClick: function(e) {
handleMenuIconClick(e) {
this.setState({ this.setState({
menuOpen: !this.state.menuOpen, menuOpen: !this.state.menuOpen,
}); });
@ -52,35 +56,38 @@ export let DropDownMenu = React.createClass({
e.stopPropagation(); e.stopPropagation();
} }
return false; return false;
}, }
handleMenuClick: function(e) {
handleMenuClick(e) {
// Event bubbles up to the menu after a link is clicked // Event bubbles up to the menu after a link is clicked
this.setState({ this.setState({
menuOpen: false, menuOpen: false,
}); });
}, }
handleWindowClick: function(e) {
handleWindowClick(e) {
if (this.state.menuOpen && if (this.state.menuOpen &&
(!this._menuDiv || !this._menuDiv.contains(e.target))) { (!this._menuDiv || !this._menuDiv.contains(e.target))) {
this.setState({ this.setState({
menuOpen: false menuOpen: false
}); });
} }
}, }
render: function() {
render() {
if (!this.state.menuOpen && this._isWindowClickBound) { if (!this.state.menuOpen && this._isWindowClickBound) {
this._isWindowClickBound = false; this._isWindowClickBound = false;
window.removeEventListener('click', this.handleWindowClick, false); window.removeEventListener('click', this.handleWindowClick, false);
} }
return ( return (
<div className="menu-container"> <div className="menu-container">
<Link ref={(span) => this._menuButton = span} button="text" icon="icon-ellipsis-v" onClick={this.handleMenuIconClick} /> <Link ref={(span) => this._menuButton = span} button="text" icon="icon-ellipsis-v" onClick={(event) => { this.handleMenuIconClick(event) }} />
{this.state.menuOpen {this.state.menuOpen
? <div ref={(div) => this._menuDiv = div} className="menu" onClick={this.handleMenuClick}> ? <div ref={(div) => this._menuDiv = div} className="menu" onClick={(event) => { this.handleMenuClick(event) }}>
{this.props.children} {this.props.children}
</div> </div>
: null} : null}
</div> </div>
); );
} }
}); }

View file

@ -1,8 +1,8 @@
import React from 'react'; import React from 'react';
import ReactModal from 'react-modal'; import ReactModal from 'react-modal';
export const ModalPage = React.createClass({ export class ModalPage extends React.Component {
render: function() { render() {
return ( return (
<ReactModal onCloseRequested={this.props.onAborted || this.props.onConfirmed} {...this.props} <ReactModal onCloseRequested={this.props.onAborted || this.props.onConfirmed} {...this.props}
className={(this.props.className || '') + ' modal-page'} className={(this.props.className || '') + ' modal-page'}
@ -13,6 +13,4 @@ export const ModalPage = React.createClass({
</ReactModal> </ReactModal>
); );
} }
}); }
export default ModalPage;

View file

@ -3,8 +3,8 @@ import ReactModal from 'react-modal';
import Link from 'component/link'; import Link from 'component/link';
export const Modal = React.createClass({ export class Modal extends React.Component {
propTypes: { static propTypes = {
type: React.PropTypes.oneOf(['alert', 'confirm', 'custom']), type: React.PropTypes.oneOf(['alert', 'confirm', 'custom']),
overlay: React.PropTypes.bool, overlay: React.PropTypes.bool,
onConfirmed: React.PropTypes.func, onConfirmed: React.PropTypes.func,
@ -13,18 +13,18 @@ export const Modal = React.createClass({
abortButtonLabel: React.PropTypes.string, abortButtonLabel: React.PropTypes.string,
confirmButtonDisabled: React.PropTypes.bool, confirmButtonDisabled: React.PropTypes.bool,
abortButtonDisabled: React.PropTypes.bool, abortButtonDisabled: React.PropTypes.bool,
}, }
getDefaultProps: function() {
return { static defaultProps = {
type: 'alert', type: 'alert',
overlay: true, overlay: true,
confirmButtonLabel: 'OK', confirmButtonLabel: 'OK',
abortButtonLabel: 'Cancel', abortButtonLabel: 'Cancel',
confirmButtonDisabled: false, confirmButtonDisabled: false,
abortButtonDisabled: false, abortButtonDisabled: false,
}; }
},
render: function() { render() {
return ( return (
<ReactModal onCloseRequested={this.props.onAborted || this.props.onConfirmed} {...this.props} <ReactModal onCloseRequested={this.props.onAborted || this.props.onConfirmed} {...this.props}
className={(this.props.className || '') + ' modal'} className={(this.props.className || '') + ' modal'}
@ -43,31 +43,35 @@ export const Modal = React.createClass({
</ReactModal> </ReactModal>
); );
} }
}); }
export const ExpandableModal = React.createClass({ export class ExpandableModal extends React.Component {
propTypes: { static propTypes = {
expandButtonLabel: React.PropTypes.string, expandButtonLabel: React.PropTypes.string,
extraContent: React.PropTypes.element, extraContent: React.PropTypes.element,
}, }
getDefaultProps: function() {
return { static defaultProps = {
confirmButtonLabel: 'OK', confirmButtonLabel: 'OK',
expandButtonLabel: 'Show More...', expandButtonLabel: 'Show More...',
hideButtonLabel: 'Show Less', hideButtonLabel: 'Show Less',
} }
},
getInitialState: function() { constructor(props) {
return { super(props);
this.state = {
expanded: false, expanded: false,
} }
}, }
toggleExpanded: function() {
toggleExpanded() {
this.setState({ this.setState({
expanded: !this.state.expanded, expanded: !this.state.expanded,
}); });
}, }
render: function() {
render() {
return ( return (
<Modal type="custom" {... this.props}> <Modal type="custom" {... this.props}>
{this.props.children} {this.props.children}
@ -77,11 +81,11 @@ export const ExpandableModal = React.createClass({
<div className="modal__buttons"> <div className="modal__buttons">
<Link button="primary" label={this.props.confirmButtonLabel} className="modal__button" onClick={this.props.onConfirmed} /> <Link button="primary" label={this.props.confirmButtonLabel} className="modal__button" onClick={this.props.onConfirmed} />
<Link button="alt" label={!this.state.expanded ? this.props.expandButtonLabel : this.props.hideButtonLabel} <Link button="alt" label={!this.state.expanded ? this.props.expandButtonLabel : this.props.hideButtonLabel}
className="modal__button" onClick={this.toggleExpanded} /> className="modal__button" onClick={() => { this.toggleExpanded() }} />
</div> </div>
</Modal> </Modal>
); );
} }
}); }
export default Modal; export default Modal;

View file

@ -1,21 +1,21 @@
import React from 'react'; import React from 'react';
export const Notice = React.createClass({ export class Notice extends React.Component {
propTypes: { static propTypes = {
isError: React.PropTypes.bool, isError: React.PropTypes.bool,
}, }
getDefaultProps: function() {
return { static defaultProps = {
isError: false, isError: false,
}; }
},
render: function() { render() {
return ( return (
<section className={'notice ' + (this.props.isError ? 'notice--error ' : '') + (this.props.className || '')}> <section className={'notice ' + (this.props.isError ? 'notice--error ' : '') + (this.props.className || '')}>
{this.props.children} {this.props.children}
</section> </section>
); );
}, }
}); }
export default Notice; export default Notice;

View file

@ -5,14 +5,25 @@ import Modal from 'component/modal';
import rewards from 'rewards'; import rewards from 'rewards';
import Link from 'component/link' import Link from 'component/link'
export let RewardLink = React.createClass({ export class RewardLink extends React.Component {
propTypes: { static propTypes = {
type: React.PropTypes.string.isRequired, type: React.PropTypes.string.isRequired,
claimed: React.PropTypes.bool, claimed: React.PropTypes.bool,
onRewardClaim: React.PropTypes.func, onRewardClaim: React.PropTypes.func,
onRewardFailure: React.PropTypes.func onRewardFailure: React.PropTypes.func
}, }
refreshClaimable: function() {
constructor(props) {
super(props);
this.state = {
claimable: true,
pending: false,
errorMessage: null
};
}
refreshClaimable() {
switch(this.props.type) { switch(this.props.type) {
case 'new_user': case 'new_user':
this.setState({ claimable: true }); this.setState({ claimable: true });
@ -26,18 +37,13 @@ export let RewardLink = React.createClass({
}.bind(this)); }.bind(this));
return; return;
} }
}, }
componentWillMount: function() {
componentWillMount() {
this.refreshClaimable(); this.refreshClaimable();
}, }
getInitialState: function() {
return { claimReward() {
claimable: true,
pending: false,
errorMessage: null
}
},
claimReward: function() {
this.setState({ this.setState({
pending: true pending: true
}) })
@ -55,28 +61,30 @@ export let RewardLink = React.createClass({
pending: false pending: false
}) })
}) })
}, }
clearError: function() {
clearError() {
if (this.props.onRewardFailure) { if (this.props.onRewardFailure) {
this.props.onRewardFailure() this.props.onRewardFailure()
} }
this.setState({ this.setState({
errorMessage: null errorMessage: null
}) })
}, }
render: function() {
render() {
return ( return (
<div className="reward-link"> <div className="reward-link">
{this.props.claimed {this.props.claimed
? <span><Icon icon="icon-check" /> Reward claimed.</span> ? <span><Icon icon="icon-check" /> Reward claimed.</span>
: <Link button={this.props.button ? this.props.button : 'alt'} disabled={this.state.pending || !this.state.claimable } : <Link button={this.props.button ? this.props.button : 'alt'} disabled={this.state.pending || !this.state.claimable }
label={ this.state.pending ? "Claiming..." : "Claim Reward"} onClick={this.claimReward} />} label={ this.state.pending ? "Claiming..." : "Claim Reward"} onClick={() => { this.claimReward() }} />}
{this.state.errorMessage ? {this.state.errorMessage ?
<Modal isOpen={true} contentLabel="Reward Claim Error" className="error-modal" onConfirmed={this.clearError}> <Modal isOpen={true} contentLabel="Reward Claim Error" className="error-modal" onConfirmed={() => { this.clearError() }}>
{this.state.errorMessage} {this.state.errorMessage}
</Modal> </Modal>
: ''} : ''}
</div> </div>
); );
} }
}); }

View file

@ -1,18 +1,19 @@
import React from 'react'; import React from 'react';
import lbry from '../lbry.js'; import lbry from '../lbry.js';
export const SnackBar = React.createClass({ export class SnackBar extends React.Component {
constructor(props) {
super(props);
_displayTime: 5, // in seconds this._displayTime = 5; // in seconds
this._hideTimeout = null;
_hideTimeout: null, this.state = {
getInitialState: function() {
return {
snacks: [] snacks: []
} };
}, }
handleSnackReceived: function(event) {
handleSnackReceived(event) {
// if (this._hideTimeout) { // if (this._hideTimeout) {
// clearTimeout(this._hideTimeout); // clearTimeout(this._hideTimeout);
// } // }
@ -20,14 +21,17 @@ export const SnackBar = React.createClass({
let snacks = this.state.snacks; let snacks = this.state.snacks;
snacks.push(event.detail); snacks.push(event.detail);
this.setState({ snacks: snacks}); this.setState({ snacks: snacks});
}, }
componentWillMount: function() {
componentWillMount() {
document.addEventListener('globalNotice', this.handleSnackReceived); document.addEventListener('globalNotice', this.handleSnackReceived);
}, }
componentWillUnmount: function() {
componentWillUnmount() {
document.removeEventListener('globalNotice', this.handleSnackReceived); document.removeEventListener('globalNotice', this.handleSnackReceived);
}, }
render: function() {
render() {
if (!this.state.snacks.length) { if (!this.state.snacks.length) {
this._hideTimeout = null; //should be unmounting anyway, but be safe? this._hideTimeout = null; //should be unmounting anyway, but be safe?
return null; return null;
@ -51,7 +55,7 @@ export const SnackBar = React.createClass({
<a className="snack-bar__action" href={snack.linkTarget}>{snack.linkText}</a> : ''} <a className="snack-bar__action" href={snack.linkTarget}>{snack.linkText}</a> : ''}
</div> </div>
); );
}, }
}); }
export default SnackBar; export default SnackBar;

View file

@ -2,21 +2,26 @@ import React from 'react';
import lbry from '../lbry.js'; import lbry from '../lbry.js';
import LoadScreen from './load_screen.js'; import LoadScreen from './load_screen.js';
var SplashScreen = React.createClass({ export class SplashScreen extends React.Component {
propTypes: { static propTypes = {
message: React.PropTypes.string, message: React.PropTypes.string,
onLoadDone: React.PropTypes.func, onLoadDone: React.PropTypes.func,
}, }
getInitialState: function() {
return { constructor(props) {
super(props);
this.state = {
details: 'Starting daemon', details: 'Starting daemon',
isLagging: false, isLagging: false,
} };
}, }
updateStatus: function() {
lbry.status().then(this._updateStatusCallback); updateStatus() {
}, lbry.status().then((status) => { this._updateStatusCallback(status) });
_updateStatusCallback: function(status) { }
_updateStatusCallback(status) {
const startupStatus = status.startup_status const startupStatus = status.startup_status
if (startupStatus.code == 'started') { if (startupStatus.code == 'started') {
// Wait until we are able to resolve a name before declaring // Wait until we are able to resolve a name before declaring
@ -40,8 +45,9 @@ var SplashScreen = React.createClass({
setTimeout(() => { setTimeout(() => {
this.updateStatus(); this.updateStatus();
}, 500); }, 500);
}, }
componentDidMount: function() {
componentDidMount() {
lbry.connect().then((isConnected) => { lbry.connect().then((isConnected) => {
if (isConnected) { if (isConnected) {
this.updateStatus(); this.updateStatus();
@ -53,10 +59,11 @@ var SplashScreen = React.createClass({
}) })
} }
}) })
}, }
render: function() {
render() {
return <LoadScreen message={this.props.message} details={this.state.details} isWarning={this.state.isLagging} /> return <LoadScreen message={this.props.message} details={this.state.details} isWarning={this.state.isLagging} />
} }
}); }
export default SplashScreen; export default SplashScreen;

View file

@ -1,38 +1,44 @@
import React from 'react'; import React from 'react';
export let ToolTip = React.createClass({ export class ToolTip extends React.Component {
propTypes: { static propTypes = {
body: React.PropTypes.string.isRequired, body: React.PropTypes.string.isRequired,
label: React.PropTypes.string.isRequired label: React.PropTypes.string.isRequired
}, }
getInitialState: function() {
return { constructor(props) {
super(props);
this.state = {
showTooltip: false, showTooltip: false,
}; };
}, }
handleClick: function() {
handleClick() {
this.setState({ this.setState({
showTooltip: !this.state.showTooltip, showTooltip: !this.state.showTooltip,
}); });
}, }
handleTooltipMouseOut: function() {
handleTooltipMouseOut() {
this.setState({ this.setState({
showTooltip: false, showTooltip: false,
}); });
}, }
render: function() {
render() {
return ( return (
<span className={'tooltip ' + (this.props.className || '')}> <span className={'tooltip ' + (this.props.className || '')}>
<a className="tooltip__link" onClick={this.handleClick}> <a className="tooltip__link" onClick={() => { this.handleClick() }}>
{this.props.label} {this.props.label}
</a> </a>
<div className={'tooltip__body ' + (this.state.showTooltip ? '' : ' hidden')} <div className={'tooltip__body ' + (this.state.showTooltip ? '' : ' hidden')}
onMouseOut={this.handleTooltipMouseOut}> onMouseOut={() => { this.handleTooltipMouseOut() }}>
{this.props.body} {this.props.body}
</div> </div>
</span> </span>
); );
} }
}); }
export default ToolTip export default ToolTip

View file

@ -51,7 +51,7 @@ class VideoPlayButton extends React.Component {
icon="icon-play" icon="icon-play"
onClick={this.onWatchClick.bind(this)} /> onClick={this.onWatchClick.bind(this)} />
{modal} {modal}
<Modal contentLabel="Not enough credits" isOpen={modal == 'notEnoughCredits'} onConfirmed={closeModal}> <Modal contentLabel="Not enough credits" isOpen={modal == 'notEnoughCredits'} onConfirmed={() => { this.closeModal() }}>
You don't have enough LBRY credits to pay for this stream. You don't have enough LBRY credits to pay for this stream.
</Modal> </Modal>
<Modal <Modal
@ -63,7 +63,7 @@ class VideoPlayButton extends React.Component {
This will purchase <strong>{title}</strong> for <strong><FilePrice uri={uri} look="plain" /></strong> credits. This will purchase <strong>{title}</strong> for <strong><FilePrice uri={uri} look="plain" /></strong> credits.
</Modal> </Modal>
<Modal <Modal
isOpen={modal == 'timedOut'} onConfirmed={closeModal} contentLabel="Timed Out"> isOpen={modal == 'timedOut'} onConfirmed={() => { this.closeModal() }} contentLabel="Timed Out">
Sorry, your download timed out :( Sorry, your download timed out :(
</Modal> </Modal>
</div>); </div>);

View file

@ -6,34 +6,40 @@ import Link from '../component/link';
const fs = require('fs'); const fs = require('fs');
const {ipcRenderer} = require('electron'); const {ipcRenderer} = require('electron');
const DeveloperPage = React.createClass({ class DeveloperPage extends React.Component {
getInitialState: function() { constructor(props) {
return { super(props);
this.state = {
showDeveloperMenu: lbry.getClientSetting('showDeveloperMenu'), showDeveloperMenu: lbry.getClientSetting('showDeveloperMenu'),
useCustomLighthouseServers: lbry.getClientSetting('useCustomLighthouseServers'), useCustomLighthouseServers: lbry.getClientSetting('useCustomLighthouseServers'),
customLighthouseServers: lbry.getClientSetting('customLighthouseServers').join('\n'), customLighthouseServers: lbry.getClientSetting('customLighthouseServers').join('\n'),
upgradePath: '', upgradePath: '',
}; };
}, }
handleShowDeveloperMenuChange: function(event) {
handleShowDeveloperMenuChange(event) {
lbry.setClientSetting('showDeveloperMenu', event.target.checked); lbry.setClientSetting('showDeveloperMenu', event.target.checked);
lbry.showMenuIfNeeded(); lbry.showMenuIfNeeded();
this.setState({ this.setState({
showDeveloperMenu: event.target.checked, showDeveloperMenu: event.target.checked,
}); });
}, }
handleUseCustomLighthouseServersChange: function(event) {
handleUseCustomLighthouseServersChange(event) {
lbry.setClientSetting('useCustomLighthouseServers', event.target.checked); lbry.setClientSetting('useCustomLighthouseServers', event.target.checked);
this.setState({ this.setState({
useCustomLighthouseServers: event.target.checked, useCustomLighthouseServers: event.target.checked,
}); });
}, }
handleUpgradeFileChange: function(event) {
handleUpgradeFileChange(event) {
this.setState({ this.setState({
upgradePath: event.target.value, upgradePath: event.target.value,
}); });
}, }
handleForceUpgradeClick: function() {
handleForceUpgradeClick() {
let upgradeSent = false; let upgradeSent = false;
if (!this.state.upgradePath) { if (!this.state.upgradePath) {
alert('Please select a file to upgrade from'); alert('Please select a file to upgrade from');
@ -51,37 +57,38 @@ const DeveloperPage = React.createClass({
alert('Failed to start upgrade. Is "' + this.state.upgradePath + '" a valid path to the upgrade?'); alert('Failed to start upgrade. Is "' + this.state.upgradePath + '" a valid path to the upgrade?');
} }
} }
}, }
render: function() {
render() {
return ( return (
<main> <main>
<section className="card"> <section className="card">
<h3>Developer Settings</h3> <h3>Developer Settings</h3>
<div className="form-row"> <div className="form-row">
<label><FormField type="checkbox" onChange={this.handleShowDeveloperMenuChange} checked={this.state.showDeveloperMenu} /> Show developer menu</label> <label><FormField type="checkbox" onChange={(event) => { this.handleShowDeveloperMenuChange() }} checked={this.state.showDeveloperMenu} /> Show developer menu</label>
</div> </div>
<div className="form-row"> <div className="form-row">
<label><FormField type="checkbox" onChange={this.handleUseCustomLighthouseServersChange} checked={this.state.useCustomLighthouseServers} /> Use custom search servers</label> <label><FormField type="checkbox" onChange={(event) => { this.handleUseCustomLighthouseServersChange() }} checked={this.state.useCustomLighthouseServers} /> Use custom search servers</label>
</div> </div>
{this.state.useCustomLighthouseServers {this.state.useCustomLighthouseServers
? <div className="form-row"> ? <div className="form-row">
<label> <label>
Custom search servers (one per line) Custom search servers (one per line)
<div><FormField type="textarea" className="developer-page__custom-lighthouse-servers" value={this.state.customLighthouseServers} onChange={this.handleCustomLighthouseServersChange} checked={this.state.debugMode} /></div> <div><FormField type="textarea" className="developer-page__custom-lighthouse-servers" value={this.state.customLighthouseServers} onChange={(event) => { this.handleCustomLighthouseServersChange() }} checked={this.state.debugMode} /></div>
</label> </label>
</div> </div>
: null} : null}
</section> </section>
<section className="card"> <section className="card">
<div className="form-row"> <div className="form-row">
<FormField name="file" ref="file" type="file" onChange={this.handleUpgradeFileChange}/> <FormField name="file" ref="file" type="file" onChange={(event) => { this.handleUpgradeFileChange() }}/>
&nbsp; &nbsp;
<Link label="Force Upgrade" button="alt" onClick={this.handleForceUpgradeClick} /> <Link label="Force Upgrade" button="alt" onClick={(event) => { this.handleForceUpgradeClick() }} />
</div> </div>
</section> </section>
</main> </main>
); );
} }
}); }
export default DeveloperPage; export default DeveloperPage;

View file

@ -5,14 +5,17 @@ import Link from 'component/link';
import SubHeader from 'component/subHeader' import SubHeader from 'component/subHeader'
import {version as uiVersion} from 'json!../../../package.json'; import {version as uiVersion} from 'json!../../../package.json';
var HelpPage = React.createClass({ class HelpPage extends React.Component {
getInitialState: function() { constructor(props) {
return { super(props);
this.state = {
versionInfo: null, versionInfo: null,
lbryId: null, lbryId: null,
}; };
}, }
componentWillMount: function() {
componentWillMount() {
lbry.getVersionInfo((info) => { lbry.getVersionInfo((info) => {
this.setState({ this.setState({
versionInfo: info, versionInfo: info,
@ -23,8 +26,9 @@ var HelpPage = React.createClass({
lbryId: info.lbry_id, lbryId: info.lbry_id,
}); });
}); });
}, }
render: function() {
render() {
let ver, osName, platform, newVerLink; let ver, osName, platform, newVerLink;
if (this.state.versionInfo) { if (this.state.versionInfo) {
ver = this.state.versionInfo; ver = this.state.versionInfo;
@ -116,6 +120,6 @@ var HelpPage = React.createClass({
</main> </main>
); );
} }
}); }
export default HelpPage; export default HelpPage;

View file

@ -6,10 +6,41 @@ import Link from 'component/link';
import rewards from 'rewards'; import rewards from 'rewards';
import Modal from 'component/modal'; import Modal from 'component/modal';
var PublishPage = React.createClass({ class PublishPage extends React.Component {
_requiredFields: ['meta_title', 'name', 'bid', 'tos_agree'], constructor(props) {
super(props);
_updateChannelList: function(channel) { this._requiredFields = ['meta_title', 'name', 'bid', 'tos_agree'];
this.state = {
channels: null,
rawName: '',
name: '',
bid: 10,
hasFile: false,
feeAmount: '',
feeCurrency: 'USD',
channel: 'anonymous',
newChannelName: '@',
newChannelBid: 10,
nameResolved: null,
myClaimExists: null,
topClaimValue: 0.0,
myClaimValue: 0.0,
myClaimMetadata: null,
copyrightNotice: '',
otherLicenseDescription: '',
otherLicenseUrl: '',
uploadProgress: 0.0,
uploaded: false,
errorMessage: null,
submitting: false,
creatingChannel: false,
modal: null,
};
}
_updateChannelList(channel) {
// Calls API to update displayed list of channels. If a channel name is provided, will select // Calls API to update displayed list of channels. If a channel name is provided, will select
// that channel at the same time (used immediately after creating a channel) // that channel at the same time (used immediately after creating a channel)
lbry.channel_list_mine().then((channels) => { lbry.channel_list_mine().then((channels) => {
@ -19,8 +50,9 @@ var PublishPage = React.createClass({
... channel ? {channel} : {} ... channel ? {channel} : {}
}); });
}); });
}, }
handleSubmit: function(event) {
handleSubmit(event) {
if (typeof event !== 'undefined') { if (typeof event !== 'undefined') {
event.preventDefault(); event.preventDefault();
} }
@ -113,51 +145,27 @@ var PublishPage = React.createClass({
} else { } else {
doPublish(); doPublish();
} }
}, }
getInitialState: function() {
return { handlePublishStarted() {
channels: null,
rawName: '',
name: '',
bid: 10,
hasFile: false,
feeAmount: '',
feeCurrency: 'USD',
channel: 'anonymous',
newChannelName: '@',
newChannelBid: 10,
nameResolved: null,
myClaimExists: null,
topClaimValue: 0.0,
myClaimValue: 0.0,
myClaimMetadata: null,
copyrightNotice: '',
otherLicenseDescription: '',
otherLicenseUrl: '',
uploadProgress: 0.0,
uploaded: false,
errorMessage: null,
submitting: false,
creatingChannel: false,
modal: null,
};
},
handlePublishStarted: function() {
this.setState({ this.setState({
modal: 'publishStarted', modal: 'publishStarted',
}); });
}, }
handlePublishStartedConfirmed: function() {
handlePublishStartedConfirmed() {
this.props.navigate('/published') this.props.navigate('/published')
}, }
handlePublishError: function(error) {
handlePublishError(error) {
this.setState({ this.setState({
submitting: false, submitting: false,
modal: 'error', modal: 'error',
errorMessage: error.message, errorMessage: error.message,
}); });
}, }
handleNameChange: function(event) {
handleNameChange(event) {
var rawName = event.target.value; var rawName = event.target.value;
if (!rawName) { if (!rawName) {
@ -224,28 +232,33 @@ var PublishPage = React.createClass({
myClaimExists: false, myClaimExists: false,
}); });
}); });
}, }
handleBidChange: function(event) {
handleBidChange(event) {
this.setState({ this.setState({
bid: event.target.value, bid: event.target.value,
}); });
}, }
handleFeeAmountChange: function(event) {
handleFeeAmountChange(event) {
this.setState({ this.setState({
feeAmount: event.target.value, feeAmount: event.target.value,
}); });
}, }
handleFeeCurrencyChange: function(event) {
handleFeeCurrencyChange(event) {
this.setState({ this.setState({
feeCurrency: event.target.value, feeCurrency: event.target.value,
}); });
}, }
handleFeePrefChange: function(feeEnabled) {
handleFeePrefChange(feeEnabled) {
this.setState({ this.setState({
isFee: feeEnabled isFee: feeEnabled
}); });
}, }
handleLicenseChange: function(event) {
handleLicenseChange(event) {
var licenseType = event.target.options[event.target.selectedIndex].getAttribute('data-license-type'); var licenseType = event.target.options[event.target.selectedIndex].getAttribute('data-license-type');
var newState = { var newState = {
copyrightChosen: licenseType == 'copyright', copyrightChosen: licenseType == 'copyright',
@ -257,30 +270,35 @@ var PublishPage = React.createClass({
} }
this.setState(newState); this.setState(newState);
}, }
handleCopyrightNoticeChange: function(event) {
handleCopyrightNoticeChange(event) {
this.setState({ this.setState({
copyrightNotice: event.target.value, copyrightNotice: event.target.value,
}); });
}, }
handleOtherLicenseDescriptionChange: function(event) {
handleOtherLicenseDescriptionChange(event) {
this.setState({ this.setState({
otherLicenseDescription: event.target.value, otherLicenseDescription: event.target.value,
}); });
}, }
handleOtherLicenseUrlChange: function(event) {
handleOtherLicenseUrlChange(event) {
this.setState({ this.setState({
otherLicenseUrl: event.target.value, otherLicenseUrl: event.target.value,
}); });
}, }
handleChannelChange: function (event) {
handleChannelChange(event) {
const channel = event.target.value; const channel = event.target.value;
this.setState({ this.setState({
channel: channel, channel: channel,
}); });
}, }
handleNewChannelNameChange: function (event) {
handleNewChannelNameChange(event) {
const newChannelName = (event.target.value.startsWith('@') ? event.target.value : '@' + event.target.value); const newChannelName = (event.target.value.startsWith('@') ? event.target.value : '@' + event.target.value);
if (newChannelName.length > 1 && !lbryuri.isValidName(newChannelName.substr(1), false)) { if (newChannelName.length > 1 && !lbryuri.isValidName(newChannelName.substr(1), false)) {
@ -293,18 +311,21 @@ var PublishPage = React.createClass({
this.setState({ this.setState({
newChannelName: newChannelName, newChannelName: newChannelName,
}); });
}, }
handleNewChannelBidChange: function (event) {
handleNewChannelBidChange(event) {
this.setState({ this.setState({
newChannelBid: event.target.value, newChannelBid: event.target.value,
}); });
}, }
handleTOSChange: function(event) {
handleTOSChange(event) {
this.setState({ this.setState({
TOSAgreed: event.target.checked, TOSAgreed: event.target.checked,
}); });
}, }
handleCreateChannelClick: function (event) {
handleCreateChannelClick(event) {
if (this.state.newChannelName.length < 5) { if (this.state.newChannelName.length < 5) {
this.refs.newChannelName.showError('LBRY channel names must be at least 4 characters in length.'); this.refs.newChannelName.showError('LBRY channel names must be at least 4 characters in length.');
return; return;
@ -330,8 +351,9 @@ var PublishPage = React.createClass({
creatingChannel: false, creatingChannel: false,
}); });
}); });
}, }
getLicenseUrl: function() {
getLicenseUrl() {
if (!this.refs.meta_license) { if (!this.refs.meta_license) {
return ''; return '';
} else if (this.state.otherLicenseChosen) { } else if (this.state.otherLicenseChosen) {
@ -339,20 +361,21 @@ var PublishPage = React.createClass({
} else { } else {
return this.refs.meta_license.getSelectedElement().getAttribute('data-url') || '' ; return this.refs.meta_license.getSelectedElement().getAttribute('data-url') || '' ;
} }
}, }
componentWillMount: function() {
componentWillMount() {
this._updateChannelList(); this._updateChannelList();
}, }
componentDidUpdate: function() {
}, onFileChange() {
onFileChange: function() {
if (this.refs.file.getValue()) { if (this.refs.file.getValue()) {
this.setState({ hasFile: true }) this.setState({ hasFile: true })
} else { } else {
this.setState({ hasFile: false }) this.setState({ hasFile: false })
} }
}, }
getNameBidHelpText: function() {
getNameBidHelpText() {
if (!this.state.name) { if (!this.state.name) {
return "Select a URL for this publish."; return "Select a URL for this publish.";
} else if (this.state.nameResolved === false) { } else if (this.state.nameResolved === false) {
@ -365,13 +388,15 @@ var PublishPage = React.createClass({
} else { } else {
return ''; return '';
} }
}, }
closeModal: function() {
closeModal() {
this.setState({ this.setState({
modal: null, modal: null,
}); });
}, }
render: function() {
render() {
if (this.state.channels === null) { if (this.state.channels === null) {
return null; return null;
} }
@ -380,7 +405,7 @@ var PublishPage = React.createClass({
return ( return (
<main className="main--single-column"> <main className="main--single-column">
<form onSubmit={this.handleSubmit}> <form onSubmit={(event) => { this.handleSubmit(event) }}>
<section className="card"> <section className="card">
<div className="card__title-primary"> <div className="card__title-primary">
<h4>Content</h4> <h4>Content</h4>
@ -389,7 +414,7 @@ var PublishPage = React.createClass({
</div> </div>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow name="file" label="File" ref="file" type="file" onChange={this.onFileChange} <FormRow name="file" label="File" ref="file" type="file" onChange={(event) => { this.onFileChange(event) }}
helper={this.state.myClaimExists ? "If you don't choose a file, the file from your existing claim will be used." : null}/> helper={this.state.myClaimExists ? "If you don't choose a file, the file from your existing claim will be used." : null}/>
</div> </div>
{ !this.state.hasFile ? '' : { !this.state.hasFile ? '' :
@ -439,7 +464,7 @@ var PublishPage = React.createClass({
<FormField type="radio" name="isFree" label={!this.state.isFee ? 'Choose price...' : 'Price ' } <FormField type="radio" name="isFree" label={!this.state.isFee ? 'Choose price...' : 'Price ' }
onChange={ () => { this.handleFeePrefChange(true) } } defaultChecked={this.state.isFee} /> onChange={ () => { this.handleFeePrefChange(true) } } defaultChecked={this.state.isFee} />
<span className={!this.state.isFee ? 'hidden' : ''}> <span className={!this.state.isFee ? 'hidden' : ''}>
<FormField type="number" className="form-field__input--inline" step="0.01" placeholder="1.00" onChange={this.handleFeeAmountChange} /> <FormField type="select" onChange={this.handleFeeCurrencyChange}> <FormField type="number" className="form-field__input--inline" step="0.01" placeholder="1.00" onChange={(event) => this.handleFeeAmountChange(event)} /> <FormField type="select" onChange={(event) => { this.handleFeeCurrencyChange(event) }}>
<option value="USD">US Dollars</option> <option value="USD">US Dollars</option>
<option value="LBC">LBRY credits</option> <option value="LBC">LBRY credits</option>
</FormField> </FormField>
@ -448,7 +473,7 @@ var PublishPage = React.createClass({
<div className="form-field__helper"> <div className="form-field__helper">
If you choose to price this content in dollars, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase. If you choose to price this content in dollars, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase.
</div> : '' } </div> : '' }
<FormRow label="License" type="select" ref="meta_license" name="license" onChange={this.handleLicenseChange}> <FormRow label="License" type="select" ref="meta_license" name="license" onChange={(event) => { this.handleLicenseChange(event) }}>
<option></option> <option></option>
<option>Public Domain</option> <option>Public Domain</option>
<option data-url="https://creativecommons.org/licenses/by/4.0/legalcode">Creative Commons Attribution 4.0 International</option> <option data-url="https://creativecommons.org/licenses/by/4.0/legalcode">Creative Commons Attribution 4.0 International</option>
@ -463,13 +488,13 @@ var PublishPage = React.createClass({
<FormField type="hidden" ref="meta_license_url" name="license_url" value={this.getLicenseUrl()} /> <FormField type="hidden" ref="meta_license_url" name="license_url" value={this.getLicenseUrl()} />
{this.state.copyrightChosen {this.state.copyrightChosen
? <FormRow label="Copyright notice" type="text" name="copyright-notice" ? <FormRow label="Copyright notice" type="text" name="copyright-notice"
value={this.state.copyrightNotice} onChange={this.handleCopyrightNoticeChange} /> value={this.state.copyrightNotice} onChange={(event) => { this.handleCopyrightNoticeChange(event) }} />
: null} : null}
{this.state.otherLicenseChosen ? {this.state.otherLicenseChosen ?
<FormRow label="License description" type="text" name="other-license-description" onChange={this.handleOtherLicenseDescriptionChange} /> <FormRow label="License description" type="text" name="other-license-description" onChange={(event) => { this.handleOtherLicenseDescriptionChange() }} />
: null} : null}
{this.state.otherLicenseChosen ? {this.state.otherLicenseChosen ?
<FormRow label="License URL" type="text" name="other-license-url" onChange={this.handleOtherLicenseUrlChange} /> <FormRow label="License URL" type="text" name="other-license-url" onChange={(event) => { this.handleOtherLicenseUrlChange(event) }} />
: null} : null}
</div> </div>
</section> </section>
@ -482,7 +507,7 @@ var PublishPage = React.createClass({
</div> </div>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow type="select" tabIndex="1" onChange={this.handleChannelChange} value={this.state.channel}> <FormRow type="select" tabIndex="1" onChange={(event) => { this.handleChannelChange(event) }} value={this.state.channel}>
<option key="anonymous" value="anonymous">Anonymous</option> <option key="anonymous" value="anonymous">Anonymous</option>
{this.state.channels.map(({name}) => <option key={name} value={name}>{name}</option>)} {this.state.channels.map(({name}) => <option key={name} value={name}>{name}</option>)}
<option key="new" value="new">New identity...</option> <option key="new" value="new">New identity...</option>
@ -490,17 +515,17 @@ var PublishPage = React.createClass({
</div> </div>
{this.state.channel == 'new' ? {this.state.channel == 'new' ?
<div className="card__content"> <div className="card__content">
<FormRow label="Name" type="text" onChange={this.handleNewChannelNameChange} ref={newChannelName => { this.refs.newChannelName = newChannelName }} <FormRow label="Name" type="text" onChange={(event) => { this.handleNewChannelNameChange(event) }} ref={newChannelName => { this.refs.newChannelName = newChannelName }}
value={this.state.newChannelName} /> value={this.state.newChannelName} />
<FormRow label="Deposit" <FormRow label="Deposit"
postfix="LBC" postfix="LBC"
step="0.01" step="0.01"
type="number" type="number"
helper={lbcInputHelp} helper={lbcInputHelp}
onChange={this.handleNewChannelBidChange} onChange={(event) => { this.handleNewChannelBidChange(event) }}
value={this.state.newChannelBid} /> value={this.state.newChannelBid} />
<div className="form-row-submit"> <div className="form-row-submit">
<Link button="primary" label={!this.state.creatingChannel ? 'Create identity' : 'Creating identity...'} onClick={this.handleCreateChannelClick} disabled={this.state.creatingChannel} /> <Link button="primary" label={!this.state.creatingChannel ? 'Create identity' : 'Creating identity...'} onClick={(event) => { this.handleCreateChannelClick(event) }} disabled={this.state.creatingChannel} />
</div> </div>
</div> </div>
: null} : null}
@ -513,7 +538,7 @@ var PublishPage = React.createClass({
<div className="card__subtitle">Where should this content permanently reside? <Link label="Read more" href="https://lbry.io/faq/naming" />.</div> <div className="card__subtitle">Where should this content permanently reside? <Link label="Read more" href="https://lbry.io/faq/naming" />.</div>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow prefix="lbry://" type="text" ref="name" placeholder="myname" value={this.state.rawName} onChange={this.handleNameChange} <FormRow prefix="lbry://" type="text" ref="name" placeholder="myname" value={this.state.rawName} onChange={(event) => { this.handleNameChange(event) }}
helper={this.getNameBidHelpText()} /> helper={this.getNameBidHelpText()} />
</div> </div>
{ this.state.rawName ? { this.state.rawName ?
@ -523,7 +548,7 @@ var PublishPage = React.createClass({
step="0.01" step="0.01"
label="Deposit" label="Deposit"
postfix="LBC" postfix="LBC"
onChange={this.handleBidChange} onChange={(event) => { this.handleBidChange(event) }}
value={this.state.bid} value={this.state.bid}
placeholder={this.state.nameResolved ? this.state.topClaimValue + 10 : 100} placeholder={this.state.nameResolved ? this.state.topClaimValue + 10 : 100}
helper={lbcInputHelp} /> helper={lbcInputHelp} />
@ -537,29 +562,29 @@ var PublishPage = React.createClass({
<div className="card__content"> <div className="card__content">
<FormRow label={ <FormRow label={
<span>I agree to the <Link href="https://www.lbry.io/termsofservice" label="LBRY terms of service" checked={this.state.TOSAgreed} /></span> <span>I agree to the <Link href="https://www.lbry.io/termsofservice" label="LBRY terms of service" checked={this.state.TOSAgreed} /></span>
} type="checkbox" name="tos_agree" ref={(field) => { this.refs.tos_agree = field }} onChange={this.handleTOSChange} /> } type="checkbox" name="tos_agree" ref={(field) => { this.refs.tos_agree = field }} onChange={(event) => { this.handleTOSChange(event)}} />
</div> </div>
</section> </section>
<div className="card-series-submit"> <div className="card-series-submit">
<Link button="primary" label={!this.state.submitting ? 'Publish' : 'Publishing...'} onClick={this.handleSubmit} disabled={this.state.submitting} /> <Link button="primary" label={!this.state.submitting ? 'Publish' : 'Publishing...'} onClick={(event) => { this.handleSubmit(event) }} disabled={this.state.submitting} />
<Link button="cancel" onClick={lbry.back} label="Cancel" /> <Link button="cancel" onClick={lbry.back} label="Cancel" />
<input type="submit" className="hidden" /> <input type="submit" className="hidden" />
</div> </div>
</form> </form>
<Modal isOpen={this.state.modal == 'publishStarted'} contentLabel="File published" <Modal isOpen={this.state.modal == 'publishStarted'} contentLabel="File published"
onConfirmed={this.handlePublishStartedConfirmed}> onConfirmed={(event) => { this.handlePublishStartedConfirmed(event) }}>
<p>Your file has been published to LBRY at the address <code>lbry://{this.state.name}</code>!</p> <p>Your file has been published to LBRY at the address <code>lbry://{this.state.name}</code>!</p>
<p>The file will take a few minutes to appear for other LBRY users. Until then it will be listed as "pending" under your published files.</p> <p>The file will take a few minutes to appear for other LBRY users. Until then it will be listed as "pending" under your published files.</p>
</Modal> </Modal>
<Modal isOpen={this.state.modal == 'error'} contentLabel="Error publishing file" <Modal isOpen={this.state.modal == 'error'} contentLabel="Error publishing file"
onConfirmed={this.closeModal}> onConfirmed={(event) => { this.closeModal(event) }}>
The following error occurred when attempting to publish your file: {this.state.errorMessage} The following error occurred when attempting to publish your file: {this.state.errorMessage}
</Modal> </Modal>
</main> </main>
); );
} }
}); }
export default PublishPage; export default PublishPage;

View file

@ -3,8 +3,17 @@ import Link from 'component/link';
import Modal from '../component/modal.js'; import Modal from '../component/modal.js';
import lbry from '../lbry.js'; import lbry from '../lbry.js';
var ReportPage = React.createClass({ class ReportPage extends React.Component {
submitMessage: function() { constructor(props) {
super(props);
this.state = {
submitting: false,
modal: null,
};
}
submitMessage() {
if (this._messageArea.value) { if (this._messageArea.value) {
this.setState({ this.setState({
submitting: true submitting: true
@ -17,19 +26,15 @@ var ReportPage = React.createClass({
}); });
this._messageArea.value = ''; this._messageArea.value = '';
} }
}, }
closeModal: function() {
closeModal() {
this.setState({ this.setState({
modal: null, modal: null,
}) })
}, }
getInitialState: function() {
return { render() {
submitting: false,
modal: null,
}
},
render: function() {
return ( return (
<main className="main--single-column"> <main className="main--single-column">
<section className="card"> <section className="card">
@ -39,7 +44,7 @@ var ReportPage = React.createClass({
<textarea ref={(t) => this._messageArea = t} cols="80" rows="10" name="message" type="text"/> <textarea ref={(t) => this._messageArea = t} cols="80" rows="10" name="message" type="text"/>
</div> </div>
<div className="form-row form-row-submit"> <div className="form-row form-row-submit">
<button onClick={this.submitMessage} className={'button-block button-primary ' + (this.state.submitting ? 'disabled' : '')}>{this.state.submitting ? 'Submitting...' : 'Submit Report'}</button> <button onClick={(event) => { this.submitMessage(event) }} className={'button-block button-primary ' + (this.state.submitting ? 'disabled' : '')}>{this.state.submitting ? 'Submitting...' : 'Submit Report'}</button>
</div> </div>
</section> </section>
<section className="card"> <section className="card">
@ -47,12 +52,12 @@ var ReportPage = React.createClass({
You can also <Link href="https://github.com/lbryio/lbry/issues" label="submit an issue on GitHub"/>. You can also <Link href="https://github.com/lbryio/lbry/issues" label="submit an issue on GitHub"/>.
</section> </section>
<Modal isOpen={this.state.modal == 'submitted'} contentLabel="Bug report submitted" <Modal isOpen={this.state.modal == 'submitted'} contentLabel="Bug report submitted"
onConfirmed={this.closeModal}> onConfirmed={(event) => { this.closeModal(event) }}>
Your bug report has been submitted! Thank you for your feedback. Your bug report has been submitted! Thank you for your feedback.
</Modal> </Modal>
</main> </main>
); );
} }
}); }
export default ReportPage; export default ReportPage;

View file

@ -4,16 +4,17 @@ import {CreditAmount, Icon} from 'component/common.js';
import SubHeader from 'component/subHeader' import SubHeader from 'component/subHeader'
import {RewardLink} from 'component/reward-link'; import {RewardLink} from 'component/reward-link';
const RewardTile = React.createClass({ export class RewardTile extends React.Component {
propTypes: { static propTypes = {
type: React.PropTypes.string.isRequired, type: React.PropTypes.string.isRequired,
title: React.PropTypes.string.isRequired, title: React.PropTypes.string.isRequired,
description: React.PropTypes.string.isRequired, description: React.PropTypes.string.isRequired,
claimed: React.PropTypes.bool.isRequired, claimed: React.PropTypes.bool.isRequired,
value: React.PropTypes.number.isRequired, value: React.PropTypes.number.isRequired,
onRewardClaim: React.PropTypes.func onRewardClaim: React.PropTypes.func
}, }
render: function() {
render() {
return ( return (
<section className="card"> <section className="card">
<div className="card__inner"> <div className="card__inner">
@ -31,19 +32,23 @@ const RewardTile = React.createClass({
</section> </section>
); );
} }
}); }
export let RewardsPage = React.createClass({ export class RewardsPage extends React.Component {
componentWillMount: function() { constructor(props) {
this.loadRewards() super(props);
},
getInitialState: function() { this.state = {
return {
userRewards: null, userRewards: null,
failed: null failed: null,
}; };
}, }
loadRewards: function() {
componentWillMount() {
this.loadRewards()
}
loadRewards() {
lbryio.call('reward', 'list', {}).then((userRewards) => { lbryio.call('reward', 'list', {}).then((userRewards) => {
this.setState({ this.setState({
userRewards: userRewards, userRewards: userRewards,
@ -51,8 +56,9 @@ export let RewardsPage = React.createClass({
}, () => { }, () => {
this.setState({failed: true }) this.setState({failed: true })
}); });
}, }
render: function() {
render() {
return ( return (
<main className="main--single-column"> <main className="main--single-column">
<SubHeader /> <SubHeader />
@ -66,6 +72,6 @@ export let RewardsPage = React.createClass({
</main> </main>
); );
} }
}); }
export default RewardsPage; export default RewardsPage;

View file

@ -3,62 +3,76 @@ import {FormField, FormRow} from 'component/form.js';
import SubHeader from 'component/subHeader' import SubHeader from 'component/subHeader'
import lbry from 'lbry.js'; import lbry from 'lbry.js';
var SettingsPage = React.createClass({ class SettingsPage extends React.Component {
setDaemonSetting: function(name, value) { constructor(props) {
super(props);
const daemonSettings = this.props.daemonSettings
this.state = {
isMaxUpload: daemonSettings && daemonSettings.max_upload != 0,
isMaxDownload: daemonSettings && daemonSettings.max_download != 0,
showNsfw: lbry.getClientSetting('showNsfw'),
showUnavailable: lbry.getClientSetting('showUnavailable'),
}
}
setDaemonSetting(name, value) {
this.props.setDaemonSetting(name, value) this.props.setDaemonSetting(name, value)
}, }
setClientSetting: function(name, value) {
setClientSetting(name, value) {
lbry.setClientSetting(name, value) lbry.setClientSetting(name, value)
this._onSettingSaveSuccess() this._onSettingSaveSuccess()
}, }
onRunOnStartChange: function (event) {
onRunOnStartChange(event) {
this.setDaemonSetting('run_on_startup', event.target.checked); this.setDaemonSetting('run_on_startup', event.target.checked);
}, }
onShareDataChange: function (event) {
onShareDataChange(event) {
this.setDaemonSetting('share_usage_data', event.target.checked); this.setDaemonSetting('share_usage_data', event.target.checked);
}, }
onDownloadDirChange: function(event) {
onDownloadDirChange(event) {
this.setDaemonSetting('download_directory', event.target.value); this.setDaemonSetting('download_directory', event.target.value);
}, }
onMaxUploadPrefChange: function(isLimited) {
onMaxUploadPrefChange(isLimited) {
if (!isLimited) { if (!isLimited) {
this.setDaemonSetting('max_upload', 0.0); this.setDaemonSetting('max_upload', 0.0);
} }
this.setState({ this.setState({
isMaxUpload: isLimited isMaxUpload: isLimited
}); });
}, }
onMaxUploadFieldChange: function(event) {
onMaxUploadFieldChange(event) {
this.setDaemonSetting('max_upload', Number(event.target.value)); this.setDaemonSetting('max_upload', Number(event.target.value));
}, }
onMaxDownloadPrefChange: function(isLimited) {
onMaxDownloadPrefChange(isLimited) {
if (!isLimited) { if (!isLimited) {
this.setDaemonSetting('max_download', 0.0); this.setDaemonSetting('max_download', 0.0);
} }
this.setState({ this.setState({
isMaxDownload: isLimited isMaxDownload: isLimited
}); });
}, }
onMaxDownloadFieldChange: function(event) {
onMaxDownloadFieldChange(event) {
this.setDaemonSetting('max_download', Number(event.target.value)); this.setDaemonSetting('max_download', Number(event.target.value));
}, }
getInitialState: function() {
const daemonSettings = this.props.daemonSettings
return { onShowNsfwChange(event) {
isMaxUpload: daemonSettings && daemonSettings.max_upload != 0,
isMaxDownload: daemonSettings && daemonSettings.max_download != 0,
showNsfw: lbry.getClientSetting('showNsfw'),
showUnavailable: lbry.getClientSetting('showUnavailable'),
}
},
onShowNsfwChange: function(event) {
lbry.setClientSetting('showNsfw', event.target.checked); lbry.setClientSetting('showNsfw', event.target.checked);
}, }
onShowUnavailableChange: function(event) {
}, onShowUnavailableChange(event) {
render: function() {
}
render() {
const { const {
daemonSettings daemonSettings
} = this.props } = this.props
@ -185,6 +199,6 @@ var SettingsPage = React.createClass({
</main> </main>
); );
} }
}); }
export default SettingsPage; export default SettingsPage;

View file

@ -1,11 +1,12 @@
import React from 'react'; import React from 'react';
import lbry from '../lbry.js'; import lbry from '../lbry.js';
var StartPage = React.createClass({ class StartPage extends React.Component {
componentWillMount: function() { componentWillMount() {
lbry.stop(); lbry.stop();
}, }
render: function() {
render() {
return ( return (
<main className="main--single-column"> <main className="main--single-column">
<h3>LBRY is Closed</h3> <h3>LBRY is Closed</h3>
@ -13,6 +14,6 @@ var StartPage = React.createClass({
</main> </main>
); );
} }
}); }
export default StartPage; export default StartPage;