improve bid/name help text

This commit is contained in:
Sean Yesmunt 2018-09-24 20:17:08 -04:00
parent b054bc096e
commit 516a3f52e8
8 changed files with 170 additions and 117 deletions

View file

@ -1,72 +1,34 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import Button from 'component/button';
import { buildURI } from 'lbry-redux';
import type { Claim } from 'types/claim';
type Props = { type Props = {
uri: ?string, uri: ?string,
isResolvingUri: boolean, isResolvingUri: boolean,
winningBidForClaimUri: ?number, amountNeededForTakeover: ?number,
myClaimForUri: ?Claim,
isStillEditing: boolean,
onEditMyClaim: (any, string) => void,
}; };
class BidHelpText extends React.PureComponent<Props> { class BidHelpText extends React.PureComponent<Props> {
render() { render() {
const { const { uri, isResolvingUri, amountNeededForTakeover } = this.props;
uri, let bidHelpText;
isResolvingUri,
winningBidForClaimUri,
myClaimForUri,
onEditMyClaim,
isStillEditing,
} = this.props;
if (!uri) { if (uri) {
return __('Create a URL for this content.'); if (isResolvingUri) {
bidHelpText = __('Checking the winning claim amount...');
} else if (!amountNeededForTakeover) {
bidHelpText = __('Any amount will give you the winning bid.');
} else {
bidHelpText = `${__('If you bid more than')} ${amountNeededForTakeover} LBC, ${__(
'when somone navigates to'
)} ${uri} ${__('it will load your published content')}.`;
}
} }
if (isStillEditing) { return (
return __(
'You are currently editing this claim. If you change the URL, you will need to reselect a file.'
);
}
if (isResolvingUri) {
return __('Checking the winning claim amount...');
}
if (myClaimForUri) {
const editUri = buildURI({
contentName: myClaimForUri.name,
claimId: myClaimForUri.claim_id,
});
return (
<React.Fragment>
{__('You already have a claim at')}
{` ${uri} `}
<Button
button="link"
label="Edit it"
onClick={() => onEditMyClaim(myClaimForUri, editUri)}
/>
<br />
{__('Publishing will update your existing claim.')}
</React.Fragment>
);
}
return winningBidForClaimUri ? (
<React.Fragment> <React.Fragment>
{__('A deposit greater than')} {winningBidForClaimUri} {__('is needed to win')} {__('This LBC remains yours and the deposit can be undone at any time.')}
{` ${uri}. `} <div>{bidHelpText}</div>
{__('However, you can still get this URL for any amount.')}
</React.Fragment> </React.Fragment>
) : (
__('Any amount will give you the winning bid.')
); );
} }
} }

View file

@ -0,0 +1,49 @@
// @flow
import * as React from 'react';
import Button from 'component/button';
import { buildURI } from 'lbry-redux';
import type { Claim } from 'types/claim';
type Props = {
uri: ?string,
myClaimForUri: ?Claim,
isStillEditing: boolean,
onEditMyClaim: (any, string) => void,
};
class NameHelpText extends React.PureComponent<Props> {
render() {
const { uri, myClaimForUri, onEditMyClaim, isStillEditing } = this.props;
let nameHelpText;
if (isStillEditing) {
nameHelpText = __(
'You are currently editing this claim. If you change the URL, you will need to reselect a file.'
);
} else if (uri && myClaimForUri) {
const editUri = buildURI({
contentName: myClaimForUri.name,
claimId: myClaimForUri.claim_id,
});
nameHelpText = (
<React.Fragment>
{__('You already have a claim at')}
{` ${uri} `}
<Button
button="link"
label="Edit it"
onClick={() => onEditMyClaim(myClaimForUri, editUri)}
/>
<br />
{__('Publishing will update your existing claim.')}
</React.Fragment>
);
}
return <React.Fragment>{nameHelpText || __('Create a URL for this content.')}</React.Fragment>;
}
}
export default NameHelpText;

View file

@ -13,6 +13,7 @@ import { CHANNEL_NEW, CHANNEL_ANONYMOUS, MINIMUM_PUBLISH_BID } from 'constants/c
import * as icons from 'constants/icons'; import * as icons from 'constants/icons';
import type { Claim } from 'types/claim'; import type { Claim } from 'types/claim';
import BidHelpText from './internal/bid-help-text'; import BidHelpText from './internal/bid-help-text';
import NameHelpText from './internal/name-help-text';
import LicenseType from './internal/license-type'; import LicenseType from './internal/license-type';
type Props = { type Props = {
@ -53,8 +54,9 @@ type Props = {
clearPublish: () => void, clearPublish: () => void,
resolveUri: string => void, resolveUri: string => void,
scrollToTop: () => void, scrollToTop: () => void,
prepareEdit: ({ }) => void, prepareEdit: ({}) => void,
resetThumbnailStatus: () => void, resetThumbnailStatus: () => void,
amountNeededForTakeover: ?number,
}; };
class PublishForm extends React.PureComponent<Props> { class PublishForm extends React.PureComponent<Props> {
@ -84,6 +86,7 @@ class PublishForm extends React.PureComponent<Props> {
// If they are midway through a channel creation, treat it as anonymous until it completes // If they are midway through a channel creation, treat it as anonymous until it completes
const channelName = channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW ? '' : channel; const channelName = channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW ? '' : channel;
// We are only going to store the full uri, but we need to resolve the uri with and without the channel name
let uri; let uri;
try { try {
uri = buildURI({ contentName: name, channelName }); uri = buildURI({ contentName: name, channelName });
@ -92,6 +95,11 @@ class PublishForm extends React.PureComponent<Props> {
} }
if (uri) { if (uri) {
if (channelName) {
// resolve without the channel name so we know the winning bid for it
const uriLessChannel = buildURI({ contentName: name });
resolveUri(uriLessChannel);
}
resolveUri(uri); resolveUri(uri);
return uri; return uri;
} }
@ -295,8 +303,9 @@ class PublishForm extends React.PureComponent<Props> {
{name && nameError && <div>{__('The URL you created is not valid')}</div>} {name && nameError && <div>{__('The URL you created is not valid')}</div>}
{!bid && <div>{__('A bid amount is required')}</div>} {!bid && <div>{__('A bid amount is required')}</div>}
{!!bid && bidError && <div>{bidError}</div>} {!!bid && bidError && <div>{bidError}</div>}
{uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS {uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS && (
&& <div>{__('Please wait for thumbnail to finish uploading')}</div>} <div>{__('Please wait for thumbnail to finish uploading')}</div>
)}
{!tosAccepted && <div>{__('You must agree to the terms of service')}</div>} {!tosAccepted && <div>{__('You must agree to the terms of service')}</div>}
{!!editingURI && {!!editingURI &&
!isStillEditing && !isStillEditing &&
@ -338,6 +347,7 @@ class PublishForm extends React.PureComponent<Props> {
thumbnailPath, thumbnailPath,
resetThumbnailStatus, resetThumbnailStatus,
isStillEditing, isStillEditing,
amountNeededForTakeover,
} = this.props; } = this.props;
const formDisabled = (!filePath && !editingURI) || publishing; const formDisabled = (!filePath && !editingURI) || publishing;
@ -350,19 +360,17 @@ class PublishForm extends React.PureComponent<Props> {
submitLabel = !publishing ? __('Publish') : __('Publishing...'); submitLabel = !publishing ? __('Publish') : __('Publishing...');
} }
const shortUri = buildURI({ contentName: name });
return ( return (
<Form onSubmit={this.handlePublish}> <Form onSubmit={this.handlePublish}>
<section className={classnames('card card--section', { 'card--disabled': publishing })}> <section className={classnames('card card--section', { 'card--disabled': publishing })}>
<div className="card__title">{__('Content')}</div> <div className="card__title">{__('Content')}</div>
<div className="card__subtitle"> <div className="card__subtitle">
{isStillEditing ? __('Editing a claim') : __('What are you publishing?')} {isStillEditing ? __('Editing a claim') : __('What are you publishing?')}{' '}
{' '}{__( {__('Read our')}{' '}
'Read our'
)}{' '}
<Button button="link" label={__('FAQ')} href="https://lbry.io/faq/how-to-publish" />{' '} <Button button="link" label={__('FAQ')} href="https://lbry.io/faq/how-to-publish" />{' '}
{__( {__('to learn more.')}
'to learn more.'
)}
</div> </div>
{(filePath || !!editingURI) && ( {(filePath || !!editingURI) && (
<div className="card-media__internal-links"> <div className="card-media__internal-links">
@ -420,12 +428,12 @@ class PublishForm extends React.PureComponent<Props> {
{uploadThumbnailStatus === THUMBNAIL_STATUSES.API_DOWN ? ( {uploadThumbnailStatus === THUMBNAIL_STATUSES.API_DOWN ? (
__('Enter a URL for your thumbnail.') __('Enter a URL for your thumbnail.')
) : ( ) : (
<React.Fragment> <React.Fragment>
{__('Upload your thumbnail (.png/.jpg/.jpeg/.gif) to')}{' '} {__('Upload your thumbnail (.png/.jpg/.jpeg/.gif) to')}{' '}
<Button button="link" label={__('spee.ch')} href="https://spee.ch/about" />.{' '} <Button button="link" label={__('spee.ch')} href="https://spee.ch/about" />.{' '}
{__('Recommended size: 800x450 (16:9)')} {__('Recommended size: 800x450 (16:9)')}
</React.Fragment> </React.Fragment>
)} )}
</div> </div>
<SelectThumbnail <SelectThumbnail
thumbnailPath={thumbnailPath} thumbnailPath={thumbnailPath}
@ -496,11 +504,12 @@ class PublishForm extends React.PureComponent<Props> {
<FormRow> <FormRow>
<FormField <FormField
stretch stretch
label={__('Name')}
prefix={`lbry://${ prefix={`lbry://${
!channel || channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW !channel || channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW
? '' ? ''
: `${channel}/` : `${channel}/`
}`} }`}
type="text" type="text"
name="content_name" name="content_name"
placeholder="myname" placeholder="myname"
@ -508,12 +517,9 @@ class PublishForm extends React.PureComponent<Props> {
onChange={event => this.handleNameChange(event.target.value)} onChange={event => this.handleNameChange(event.target.value)}
error={nameError} error={nameError}
helper={ helper={
<BidHelpText <NameHelpText
isStillEditing={isStillEditing} isStillEditing={isStillEditing}
uri={uri} uri={uri}
editingURI={editingURI}
isResolvingUri={isResolvingUri}
winningBidForClaimUri={winningBidForClaimUri}
myClaimForUri={myClaimForUri} myClaimForUri={myClaimForUri}
onEditMyClaim={this.editExistingClaim} onEditMyClaim={this.editExistingClaim}
/> />
@ -534,8 +540,14 @@ class PublishForm extends React.PureComponent<Props> {
min="0" min="0"
disabled={!name} disabled={!name}
onChange={event => this.handleBidChange(parseFloat(event.target.value))} onChange={event => this.handleBidChange(parseFloat(event.target.value))}
helper={__('This LBC remains yours and the deposit can be undone at any time.')}
placeholder={winningBidForClaimUri ? winningBidForClaimUri + 0.1 : 0.1} placeholder={winningBidForClaimUri ? winningBidForClaimUri + 0.1 : 0.1}
helper={
<BidHelpText
uri={shortUri}
isResolvingUri={isResolvingUri}
amountNeededForTakeover={amountNeededForTakeover}
/>
}
/> />
</div> </div>
</section> </section>

View file

@ -81,6 +81,7 @@ class FilePage extends React.Component<Props> {
this.checkSubscription(this.props); this.checkSubscription(this.props);
setViewed(uri); setViewed(uri);
console.log('claim', this.props.claim);
} }
componentWillReceiveProps(nextProps: Props) { componentWillReceiveProps(nextProps: Props) {

View file

@ -1,10 +1,12 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doResolveUri, selectClaimsByUri, selectResolvingUris, selectBalance } from 'lbry-redux'; import { doResolveUri, selectBalance } from 'lbry-redux';
import { doNavigate } from 'redux/actions/navigation'; import { doNavigate } from 'redux/actions/navigation';
import { import {
selectPublishFormValues, selectPublishFormValues,
selectIsStillEditing, selectIsStillEditing,
selectMyClaimForUri, selectMyClaimForUri,
selectIsResolvingPublishUris,
selectTakeOverAmount,
} from 'redux/selectors/publish'; } from 'redux/selectors/publish';
import { import {
doResetThumbnailStatus, doResetThumbnailStatus,
@ -15,43 +17,18 @@ import {
} from 'redux/actions/publish'; } from 'redux/actions/publish';
import PublishPage from './view'; import PublishPage from './view';
const select = state => { const select = state => ({
const isStillEditing = selectIsStillEditing(state); ...selectPublishFormValues(state),
const myClaimForUri = selectMyClaimForUri(state); // The winning claim for a short lbry uri
const publishState = selectPublishFormValues(state); amountNeededForTakeover: selectTakeOverAmount(state),
const { uri } = publishState; // My previously published claims under this short lbry uri
myClaimForUri: selectMyClaimForUri(state),
const resolvingUris = selectResolvingUris(state); // If I clicked the "edit" button, have I changed the uri?
let isResolvingUri = false; // Need this to make it easier to find the source on previously published content
if (uri) { isStillEditing: selectIsStillEditing(state),
isResolvingUri = resolvingUris.includes(uri); balance: selectBalance(state),
} isResolvingUri: selectIsResolvingPublishUris(state),
});
let claimForUri;
let winningBidForClaimUri;
if (!myClaimForUri) {
// if the uri isn't from a users claim, find the winning bid needed for the vanity url
// in the future we may want to display this on users claims
// ex: "you own this, for 5 more lbc you will win this claim"
const claimsByUri = selectClaimsByUri(state);
claimForUri = claimsByUri[uri];
winningBidForClaimUri = claimForUri ? claimForUri.effective_amount : null;
}
return {
...publishState,
isResolvingUri,
// The winning claim for a short lbry uri
claimForUri,
winningBidForClaimUri,
// My previously published claims under this short lbry uri
myClaimForUri,
// If I clicked the "edit" button, have I changed the uri?
// Need this to make it easier to find the source on previously published content
isStillEditing,
balance: selectBalance(state),
};
};
const perform = dispatch => ({ const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)), updatePublishForm: value => dispatch(doUpdatePublishForm(value)),

View file

@ -3,7 +3,7 @@ import * as ACTIONS from 'constants/action_types';
const getCurrentPath = () => { const getCurrentPath = () => {
const { hash } = document.location; const { hash } = document.location;
if (hash !== '') return hash.replace(/^#/, ''); if (hash !== '') return hash.replace(/^#/, '');
return '/discover'; return '/publish';
}; };
const reducers = {}; const reducers = {};

View file

@ -1,5 +1,12 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { parseURI, selectClaimsById, selectMyClaimsWithoutChannels } from 'lbry-redux'; import {
parseURI,
selectClaimsById,
selectMyClaimsWithoutChannels,
selectResolvingUris,
buildURI,
selectClaimsByUri,
} from 'lbry-redux';
const selectState = state => state.publish || {}; const selectState = state => state.publish || {};
@ -93,3 +100,48 @@ export const selectMyClaimForUri = createSelector(
); );
} }
); );
export const selectIsResolvingPublishUris = createSelector(
selectState,
selectResolvingUris,
({ uri, name }, resolvingUris) => {
if (uri) {
const isResolvingUri = resolvingUris.includes(uri);
const { isChannel } = parseURI(uri);
let isResolvingShortUri;
if (isChannel) {
const shortUri = buildURI({ contentName: name });
isResolvingShortUri = resolvingUris.includes(shortUri);
}
return isResolvingUri || isResolvingShortUri;
}
return false;
}
);
export const selectTakeOverAmount = createSelector(
selectState,
selectMyClaimForUri,
selectClaimsByUri,
({ name }, myClaimForUri, claimsByUri) => {
// We only care about the winning claim for the short uri
const shortUri = buildURI({ contentName: name });
const claimForShortUri = claimsByUri[shortUri];
if (!myClaimForUri && claimForShortUri) {
return claimForShortUri.effective_amount;
} else if (myClaimForUri && claimForShortUri) {
// https://github.com/lbryio/lbry/issues/1476
// We should check the current effective_amount on my claim to see how much additional lbc
// is needed to win the claim. Currently this is not possible during a takeover.
// With this, we could say something like, "You have x lbc in support, if you bid y additional LBC you will control the claim"
// For now just ignore supports. We will just show the winning claim's bid amount
return claimForShortUri.effective_amount || claimForShortUri.amount;
}
return null;
}
);

View file

@ -97,7 +97,7 @@
.form-field__help { .form-field__help {
color: var(--color-help); color: var(--color-help);
padding-top: $spacing-vertical * 2/3; padding-top: $spacing-vertical * 1/3;
} }
.form-field__error { .form-field__error {