import React from 'react';
import lbry from '../lbry.js';
import uri from '../uri.js';
import {FormField, FormRow} from '../component/form.js';
import {Link} from '../component/link.js';
import rewards from '../rewards.js';
import lbryio from '../lbryio.js';
import Modal from '../component/modal.js';
var PublishPage = React.createClass({
_requiredFields: ['meta_title', 'name', 'bid', 'tos_agree'],
_requestPublishReward: function() {
lbryio.call('reward', 'list', {}).then(function(userRewards) {
//already rewarded
if (userRewards.filter(function (reward) {
return reward.RewardType == rewards.TYPE_FIRST_PUBLISH && reward.TransactionID;
}).length) {
return;
}
else {
rewards.claimReward(rewards.TYPE_FIRST_PUBLISH)
}
});
},
_updateChannelList: function(channel) {
// 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)
lbry.channel_list_mine().then((channels) => {
rewards.claimReward(rewards.TYPE_FIRST_CHANNEL).then(() => {}, () => {})
this.setState({
channels: channels,
... channel ? {channel} : {}
});
});
},
handleSubmit: function(event) {
if (typeof event !== 'undefined') {
event.preventDefault();
}
this.setState({
submitting: true,
});
let checkFields = this._requiredFields;
if (!this.state.myClaimExists) {
checkFields.unshift('file');
}
let missingFieldFound = false;
for (let fieldName of checkFields) {
const field = this.refs[fieldName];
if (field) {
if (field.getValue() === '' || field.getValue() === false) {
field.showRequiredError();
if (!missingFieldFound) {
field.focus();
missingFieldFound = true;
}
} else {
field.clearError();
}
}
}
if (missingFieldFound) {
this.setState({
submitting: false,
});
return;
}
if (this.state.nameIsMine) {
// Pre-populate with existing metadata
var metadata = Object.assign({}, this.state.myClaimMetadata);
if (this.refs.file.getValue() !== '') {
delete metadata.sources;
}
} else {
var metadata = {};
}
for (let metaField of ['title', 'description', 'thumbnail', 'license', 'license_url', 'language']) {
var value = this.refs['meta_' + metaField].getValue();
if (value !== '') {
metadata[metaField] = value;
}
}
metadata.nsfw = Boolean(parseInt(!!this.refs.meta_nsfw.getValue()));
const licenseUrl = this.refs.meta_license_url.getValue();
if (licenseUrl) {
metadata.license_url = licenseUrl;
}
var doPublish = () => {
var publishArgs = {
name: this.state.name,
bid: parseFloat(this.state.bid),
metadata: metadata,
... this.state.channel != 'new' && this.state.channel != 'anonymous' ? {channel_name: this.state.channel} : {},
};
if (this.refs.file.getValue() !== '') {
publishArgs.file_path = this.refs.file.getValue();
}
lbry.publish(publishArgs, (message) => {
this.handlePublishStarted();
}, null, (error) => {
this.handlePublishError(error);
});
};
if (this.state.isFee) {
lbry.getUnusedAddress((address) => {
metadata.fee = {};
metadata.fee[this.state.feeCurrency] = {
amount: parseFloat(this.state.feeAmount),
address: address,
};
doPublish();
});
} else {
doPublish();
}
},
getInitialState: function() {
return {
channels: null,
rawName: '',
name: '',
bid: 1,
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({
modal: 'publishStarted',
});
},
handlePublishStartedConfirmed: function() {
window.location = "?published";
},
handlePublishError: function(error) {
this.setState({
submitting: false,
modal: 'error',
errorMessage: error.message,
});
},
handleNameChange: function(event) {
var rawName = event.target.value;
if (!rawName) {
this.setState({
rawName: '',
name: '',
nameResolved: false,
});
return;
}
if (!lbry.nameIsValid(rawName, false)) {
this.refs.name.showError('LBRY names must contain only letters, numbers and dashes.');
return;
}
const name = rawName.toLowerCase();
this.setState({
rawName: rawName,
name: name,
nameResolved: null,
myClaimExists: null,
});
lbry.getMyClaim(name, (myClaimInfo) => {
if (name != this.state.name) {
// A new name has been typed already, so bail
return;
}
this.setState({
myClaimExists: !!myClaimInfo,
});
lbry.resolve({uri: name}).then((claimInfo) => {
if (name != this.state.name) {
return;
}
if (!claimInfo) {
this.setState({
nameResolved: false,
});
} else {
const topClaimIsMine = (myClaimInfo && myClaimInfo.claim.amount >= claimInfo.claim.amount);
const newState = {
nameResolved: true,
topClaimValue: parseFloat(claimInfo.claim.amount),
myClaimExists: !!myClaimInfo,
myClaimValue: myClaimInfo ? parseFloat(myClaimInfo.claim.amount) : null,
myClaimMetadata: myClaimInfo ? myClaimInfo.value : null,
topClaimIsMine: topClaimIsMine,
};
if (topClaimIsMine) {
newState.bid = myClaimInfo.claim.amount;
} else if (this.state.myClaimMetadata) {
// Just changed away from a name we have a claim on, so clear pre-fill
newState.bid = '';
}
this.setState(newState);
}
}, () => { // Assume an error means the name is available
this.setState({
name: name,
nameResolved: false,
myClaimExists: false,
});
});
});
},
handleBidChange: function(event) {
this.setState({
bid: event.target.value,
});
},
handleFeeAmountChange: function(event) {
this.setState({
feeAmount: event.target.value,
});
},
handleFeeCurrencyChange: function(event) {
this.setState({
feeCurrency: event.target.value,
});
},
handleFeePrefChange: function(feeEnabled) {
this.setState({
isFee: feeEnabled
});
},
handleLicenseChange: function(event) {
var licenseType = event.target.options[event.target.selectedIndex].getAttribute('data-license-type');
var newState = {
copyrightChosen: licenseType == 'copyright',
otherLicenseChosen: licenseType == 'other',
};
if (licenseType == 'copyright') {
newState.copyrightNotice = 'All rights reserved.'
}
this.setState(newState);
},
handleCopyrightNoticeChange: function(event) {
this.setState({
copyrightNotice: event.target.value,
});
},
handleOtherLicenseDescriptionChange: function(event) {
this.setState({
otherLicenseDescription: event.target.value,
});
},
handleOtherLicenseUrlChange: function(event) {
this.setState({
otherLicenseUrl: event.target.value,
});
},
handleChannelChange: function (event) {
const channel = event.target.value;
this.setState({
channel: channel,
});
},
handleNewChannelNameChange: function (event) {
const newChannelName = (event.target.value.startsWith('@') ? event.target.value : '@' + event.target.value);
if (newChannelName.length > 1 && !lbry.nameIsValid(newChannelName.substr(1), false)) {
this.refs.newChannelName.showError('LBRY channel names must contain only letters, numbers and dashes.');
return;
} else {
this.refs.newChannelName.clearError()
}
this.setState({
newChannelName: newChannelName,
});
},
handleNewChannelBidChange: function (event) {
this.setState({
newChannelBid: event.target.value,
});
},
handleTOSChange: function(event) {
this.setState({
TOSAgreed: event.target.checked,
});
},
handleCreateChannelClick: function (event) {
if (this.state.newChannelName.length < 5) {
this.refs.newChannelName.showError('LBRY channel names must be at least 4 characters in length.');
return;
}
this.setState({
creatingChannel: true,
});
const newChannelName = this.state.newChannelName;
lbry.channel_new({channel_name: newChannelName, amount: parseInt(this.state.newChannelBid)}).then(() => {
setTimeout(() => {
this.setState({
creatingChannel: false,
});
this._updateChannelList(newChannelName);
}, 5000);
}, (error) => {
// TODO: better error handling
this.refs.newChannelName.showError('Unable to create channel due to an internal error.');
this.setState({
creatingChannel: false,
});
});
},
getLicenseUrl: function() {
if (!this.refs.meta_license) {
return '';
} else if (this.state.otherLicenseChosen) {
return this.state.otherLicenseUrl;
} else {
return this.refs.meta_license.getSelectedElement().getAttribute('data-url') || '' ;
}
},
componentWillMount: function() {
this._updateChannelList();
// this._requestPublishReward();
},
componentDidMount: function() {
document.title = "Publish";
},
componentDidUpdate: function() {
},
onFileChange: function() {
if (this.refs.file.getValue()) {
this.setState({ hasFile: true })
} else {
this.setState({ hasFile: false })
}
},
getNameBidHelpText: function() {
if (!this.state.name) {
return "Select a URL for this publish.";
} else if (this.state.nameResolved === false) {
return "This URL is unused.";
} else if (this.state.myClaimExists) {
return "You have already used this URL. Publishing to it again will update your previous publish."
} else if (this.state.topClaimValue) {
return A deposit of at least {this.state.topClaimValue} {this.state.topClaimValue == 1 ? 'credit ' : 'credits '}
is required to win {this.state.name}. However, you can still get a permanent URL for any amount.
} else {
return '';
}
},
closeModal: function() {
this.setState({
modal: null,
});
},
render: function() {
if (this.state.channels === null) {
return null;
}
const lbcInputHelp = "This LBC remains yours and the deposit can be undone at any time."
return (
Your file has been published to LBRY at the address lbry://{this.state.name}!
You will now be taken to your My Files page, where your newly published file will be listed. The file will take a few minutes to appear for other LBRY users; until then it will be listed as "pending."
The following error occurred when attempting to publish your file: {this.state.errorMessage}
);
}
});
export default PublishPage;