Progress towards working publish

This commit is contained in:
6ea86b96 2017-06-18 00:59:18 +07:00
parent 3d3b739387
commit 54a0c95e16
5 changed files with 253 additions and 107 deletions

View file

@ -301,3 +301,32 @@ export function doFetchChannelListMine() {
lbry.channel_list_mine().then(callback);
};
}
export function doCreateChannel(name, amount) {
return function(dispatch, getState) {
dispatch({
type: types.CREATE_CHANNEL_STARTED,
});
return new Promise((resolve, reject) => {
lbry
.channel_new({
channel_name: name,
amount: parseFloat(amount),
})
.then(
channelClaim => {
channelClaim.name = name;
dispatch({
type: types.CREATE_CHANNEL_COMPLETED,
data: { channelClaim },
});
resolve(channelClaim);
},
err => {
resolve(err);
}
);
});
};
}

View file

@ -64,6 +64,8 @@ export const FETCH_CHANNEL_LIST_MINE_STARTED =
"FETCH_CHANNEL_LIST_MINE_STARTED";
export const FETCH_CHANNEL_LIST_MINE_COMPLETED =
"FETCH_CHANNEL_LIST_MINE_COMPLETED";
export const CREATE_CHANNEL_STARTED = "CREATE_CHANNEL_STARTED";
export const CREATE_CHANNEL_COMPLETED = "CREATE_CHANNEL_COMPLETED";
// Search
export const SEARCH_STARTED = "SEARCH_STARTED";

View file

@ -13,6 +13,7 @@ import {
doFetchClaimListMine,
doFetchChannelListMine,
doResolveUri,
doCreateChannel,
} from "actions/content";
import rewards from "rewards";
import PublishPage from "./view";
@ -33,6 +34,7 @@ const perform = dispatch => ({
dispatch(doClaimRewardType(rewards.TYPE_FIRST_CHANNEL)),
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
resolveUri: uri => dispatch(doResolveUri(uri)),
createChannel: (name, amount) => dispatch(doCreateChannel(name, amount)),
});
export default connect(select, perform)(PublishPage);

View file

@ -216,6 +216,10 @@ class PublishPage extends React.PureComponent {
handleNameChange(event) {
var rawName = event.target.value;
this.nameChanged(rawName);
}
nameChanged(rawName) {
if (!rawName) {
this.setState({
rawName: "",
@ -233,15 +237,26 @@ class PublishPage extends React.PureComponent {
return;
}
let channel = "";
if (this.state.channel !== "anonymous") channel = this.state.channel;
const name = rawName.toLowerCase();
const uri = lbryuri.normalize(name);
const uri = lbryuri.build({ contentName: name, channelName: channel });
this.setState({
rawName: rawName,
name: name,
uri,
});
this.props.resolveUri(uri);
if (this.resolveUriTimeout) {
clearTimeout(this.resolveUriTimeout);
this.resolveUriTimeout = undefined;
}
const resolve = () => this.props.resolveUri(uri);
this.resolveUriTimeout = setTimeout(resolve.bind(this), 500, {
once: true,
});
}
handleBidChange(event) {
@ -302,40 +317,12 @@ class PublishPage extends React.PureComponent {
});
}
handleChannelChange(event) {
const channel = event.target.value;
handleChannelChange(channelName) {
this.setState({
channel: channel,
});
}
handleNewChannelNameChange(event) {
const newChannelName = event.target.value.startsWith("@")
? event.target.value
: "@" + event.target.value;
if (
newChannelName.length > 1 &&
!lbryuri.isValidName(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(event) {
this.setState({
newChannelBid: event.target.value,
channel: channelName,
});
const nameChanged = () => this.nameChanged(this.state.rawName);
setTimeout(nameChanged.bind(this), 500, { once: true });
}
handleTOSChange(event) {
@ -413,7 +400,8 @@ class PublishPage extends React.PureComponent {
getNameBidHelpText() {
if (
this.state.uri &&
this.props.resolvingUris.indexOf(this.state.uri) !== -1
this.props.resolvingUris.indexOf(this.state.uri) !== -1 &&
this.claim() === undefined
) {
return <BusyMessage />;
} else if (!this.state.name) {
@ -700,77 +688,11 @@ class PublishPage extends React.PureComponent {
</div>
</section>
<section className="card">
<div className="card__title-primary">
<h4>{__("Identity")}</h4>
<div className="card__subtitle">
{__("Who created this content?")}
</div>
</div>
<div className="card__content">
{this.props.fetchingChannels
? <BusyMessage message="Fetching identities" />
: <FormRow
type="select"
tabIndex="1"
onChange={event => {
this.handleChannelChange(event);
}}
value={this.state.channel}
>
<option key="anonymous" value="anonymous">
{__("Anonymous")}
</option>
{this.props.channels.map(({ name }) =>
<option key={name} value={name}>{name}</option>
)}
<option key="new" value="new">
{__("New identity...")}
</option>
</FormRow>}
</div>
{this.state.channel == "new"
? <div className="card__content">
<FormRow
label={__("Name")}
type="text"
onChange={event => {
this.handleNewChannelNameChange(event);
}}
ref={newChannelName => {
this.refs.newChannelName = newChannelName;
}}
value={this.state.newChannelName}
/>
<FormRow
label={__("Deposit")}
postfix="LBC"
step="0.01"
min="0"
type="number"
helper={lbcInputHelp}
onChange={event => {
this.handleNewChannelBidChange(event);
}}
value={this.state.newChannelBid}
/>
<div className="form-row-submit">
<Link
button="primary"
label={
!this.state.creatingChannel
? __("Create identity")
: __("Creating identity...")
}
onClick={event => {
this.handleCreateChannelClick(event);
}}
disabled={this.state.creatingChannel}
/>
</div>
</div>
: null}
</section>
<ChannelSection
{...this.props}
handleChannelChange={this.handleChannelChange.bind(this)}
channel={this.state.channel}
/>
<section className="card">
<div className="card__title-primary">
@ -898,4 +820,175 @@ class PublishPage extends React.PureComponent {
}
}
class ChannelSection extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
newChannelName: "@",
newChannelBid: 10,
addingChannel: false,
};
}
handleChannelChange(event) {
const channel = event.target.value;
if (channel === "new") this.setState({ addingChannel: true });
else {
this.setState({ addingChannel: false });
this.props.handleChannelChange(event.target.value);
}
}
handleNewChannelNameChange(event) {
const newChannelName = event.target.value.startsWith("@")
? event.target.value
: "@" + event.target.value;
if (
newChannelName.length > 1 &&
!lbryuri.isValidName(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,
});
}
handleNewChannelBidChange(event) {
this.setState({
newChannelBid: event.target.value,
});
}
handleCreateChannelClick(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;
const amount = parseFloat(this.state.newChannelBid);
this.setState({
creatingChannel: true,
});
const success = (() => {
this.setState({
creatingChannel: false,
addingChannel: false,
channel: newChannelName,
});
this.props.handleChannelChange(newChannelName);
}).bind(this);
const failure = (err => {
this.setState({
creatingChannel: false,
});
this.refs.newChannelName.showError(
__("Unable to create channel due to an internal error.")
);
}).bind(this);
this.props.createChannel(newChannelName, amount).then(success, failure);
}
render() {
const lbcInputHelp = __(
"This LBC remains yours and the deposit can be undone at any time."
);
const { fetchingChannels, channels } = this.props;
let channelContent = [];
if (channels.length > 0) {
channelContent.push(
<FormRow
key={this.props.channel}
type="select"
tabIndex="1"
onChange={this.handleChannelChange.bind(this)}
value={this.props.channel}
>
<option key="anonymous" value="anonymous">
{__("Anonymous")}
</option>
{this.props.channels.map(({ name }) =>
<option key={name} value={name}>{name}</option>
)}
<option key="new" value="new">
{__("New identity...")}
</option>
</FormRow>
);
if (fetchingChannels) {
channelContent.push(
<BusyMessage message="Updating channels" key="something" />
);
}
} else if (fetchingChannels) {
channelContent.push(<BusyMessage message="Loading channels" />);
}
return (
<section className="card">
<div className="card__title-primary">
<h4>{__("Identity")}</h4>
<div className="card__subtitle">
{__("Who created this content?")}
</div>
</div>
<div className="card__content">
{channelContent}
</div>
{this.state.addingChannel &&
<div className="card__content">
<FormRow
label={__("Name")}
type="text"
onChange={event => {
this.handleNewChannelNameChange(event);
}}
value={this.state.newChannelName}
/>
<FormRow
label={__("Deposit")}
postfix="LBC"
step="0.1"
min="0"
type="number"
helper={lbcInputHelp}
ref="newChannelName"
onChange={this.handleNewChannelBidChange.bind(this)}
value={this.state.newChannelBid}
/>
<div className="form-row-submit">
<Link
button="primary"
label={
!this.state.creatingChannel
? __("Create identity")
: __("Creating identity...")
}
onClick={this.handleCreateChannelClick.bind(this)}
disabled={this.state.creatingChannel}
/>
</div>
</div>}
</section>
);
}
}
export default PublishPage;

View file

@ -15,7 +15,13 @@ reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) {
byUri[uri] = claim.claim_id;
} else if (claim === undefined && certificate !== undefined) {
byId[certificate.claim_id] = certificate;
byUri[uri] = certificate.claim_id;
// Don't point URI at the channel certificate unless it actually is
// a channel URI. This is brittle.
if (!uri.split(certificate.name)[1].match(/\//)) {
byUri[uri] = certificate.claim_id;
} else {
byUri[uri] = null;
}
} else {
byUri[uri] = null;
}
@ -85,6 +91,20 @@ reducers[types.FETCH_CHANNEL_CLAIMS_COMPLETED] = function(state, action) {
});
};
reducers[types.CREATE_CHANNEL_COMPLETED] = function(state, action) {
const { channelClaim } = action.data;
const { byId } = state;
const myChannelClaims = new Set(state.myChannelClaims);
byId[channelClaim.claim_id] = channelClaim;
myChannelClaims.add(channelClaim.claim_id);
return Object.assign({}, state, {
byId,
myChannelClaims,
});
};
export default function reducer(state = defaultState, action) {
const handler = reducers[action.type];
if (handler) return handler(state, action);