Discovery fixes #2576

Merged
neb-b merged 10 commits from discovery-fixes into master 2019-06-28 09:27:56 +02:00
59 changed files with 1265 additions and 913 deletions
Showing only changes of commit f9269ae969 - Show all commits

View file

@ -48,4 +48,5 @@ declare type PublishParams = {
},
claim: StreamClaim,
nsfw: boolean,
tags: Array<Tag>,
};

View file

@ -1,4 +1,5 @@
// @flow
import type { Node } from 'react';
import React, { forwardRef } from 'react';
import Icon from 'component/common/icon';
import classnames from 'classnames';
@ -14,13 +15,12 @@ type Props = {
icon: ?string,
iconRight: ?string,
disabled: ?boolean,
children: ?React.Node,
children: ?Node,
navigate: ?string,
className: ?string,
description: ?string,
type: string,
button: ?string, // primary, secondary, alt, link
iconColor?: string,
iconSize?: number,
constrict: ?boolean, // to shorten the button and ellipsis, only use for links
activeClass?: string,
@ -31,7 +31,9 @@ type Props = {
onMouseLeave: ?(any) => any,
};
const Button = forwardRef((props: Props, ref) => {
// use forwardRef to allow consumers to pass refs to the button content if they want to
// flow requires forwardRef have default type arguments passed to it
const Button = forwardRef<any, {}>((props: Props, ref: any) => {
const {
type = 'button',
onClick,
@ -48,7 +50,6 @@ const Button = forwardRef((props: Props, ref) => {
className,
description,
button,
iconColor,
iconSize,
constrict,
activeClass,
@ -74,10 +75,10 @@ const Button = forwardRef((props: Props, ref) => {
const content = (
<span className="button__content">
{icon && <Icon icon={icon} iconColor={iconColor} size={iconSize} />}
{icon && <Icon icon={icon} size={iconSize} />}
{label && <span className="button__label">{label}</span>}
{children && children}
{iconRight && <Icon icon={iconRight} iconColor={iconColor} size={iconSize} />}
{iconRight && <Icon icon={iconRight} size={iconSize} />}
</span>
);

View file

@ -2,7 +2,7 @@
import type { Node } from 'react';
import React from 'react';
import classnames from 'classnames';
import ClaimListItem from 'component/claimListItem';
import ClaimPreview from 'component/claimPreview';
import Spinner from 'component/spinner';
import { FormField } from 'component/common/form';
import usePersistedState from 'util/use-persisted-state';
@ -36,10 +36,10 @@ export default function ClaimList(props: Props) {
return (
<section className={classnames('file-list')}>
{header !== false && (
<div className={classnames('file-list__header', { 'file-list__header--small': type === 'small' })}>
<div className={classnames('claim-list__header', { 'claim-list__header--small': type === 'small' })}>
{header || (
<FormField
className="file-list__dropdown"
className="claim-list__dropdown"
type="select"
name="file_sort"
value={currentSort}
@ -50,16 +50,16 @@ export default function ClaimList(props: Props) {
</FormField>
)}
{loading && <Spinner light type="small" />}
<div className="file-list__alt-controls">{headerAltControls}</div>
<div className="claim-list__alt-controls">{headerAltControls}</div>
</div>
)}
{meta && <div className="file-list__meta">{meta}</div>}
{meta && <div className="claim-list__meta">{meta}</div>}
{hasUris && (
<ul>
{sortedUris.map((uri, index) => (
kauffj commented 2019-06-27 22:10:01 +02:00 (Migrated from github.com)
Review

good refactor

good refactor
<React.Fragment key={uri}>
<ClaimListItem uri={uri} type={type} />
{index === 4 && injectedItem && <li className="file-list__item--injected">{injectedItem}</li>}
<ClaimPreview uri={uri} type={type} />
{index === 4 && injectedItem && <li className="claim-list__item--injected">{injectedItem}</li>}
</React.Fragment>
))}
</ul>

View file

@ -70,7 +70,7 @@ function ClaimListDiscover(props: Props) {
const header = (
<h1 className="card__title--flex">
<FormField
className="file-list__dropdown"
className="claim-list__dropdown"
type="select"
name="trending_sort"
value={typeSort}
@ -89,7 +89,7 @@ function ClaimListDiscover(props: Props) {
<FormField
type="select"
name="trending_overview"
className="file-list__dropdown"
className="claim-list__dropdown"
value={personalSort}
onChange={e => setPersonalSort(e.target.value)}
>
@ -107,7 +107,7 @@ function ClaimListDiscover(props: Props) {
<React.Fragment>
{typeSort === 'top' && (
<FormField
className="file-list__dropdown"
className="claim-list__dropdown"
type="select"
name="trending_time"
value={timeSort}

View file

@ -11,7 +11,7 @@ import {
} from 'lbry-redux';
import { selectBlackListedOutpoints } from 'lbryinc';
import { selectShowNsfw } from 'redux/selectors/settings';
import ClaimListItem from './view';
import ClaimPreview from './view';
const select = (state, props) => ({
pending: makeSelectClaimIsPending(props.uri)(state),
@ -32,4 +32,4 @@ const perform = dispatch => ({
export default connect(
select,
perform
)(ClaimListItem);
)(ClaimPreview);

View file

@ -0,0 +1,35 @@
import { connect } from 'react-redux';
import {
doResolveUri,
makeSelectClaimForUri,
makeSelectIsUriResolving,
makeSelectClaimIsMine,
makeSelectClaimIsPending,
makeSelectThumbnailForUri,
makeSelectTitleForUri,
makeSelectClaimIsNsfw,
} from 'lbry-redux';
import { selectBlackListedOutpoints } from 'lbryinc';
import { selectShowNsfw } from 'redux/selectors/settings';
import ClaimPreview from './view';
const select = (state, props) => ({
pending: makeSelectClaimIsPending(props.uri)(state),
claim: makeSelectClaimForUri(props.uri)(state),
obscureNsfw: !selectShowNsfw(state),
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
thumbnail: makeSelectThumbnailForUri(props.uri)(state),
title: makeSelectTitleForUri(props.uri)(state),
nsfw: makeSelectClaimIsNsfw(props.uri)(state),
blackListedOutpoints: selectBlackListedOutpoints(state),
});
const perform = dispatch => ({
resolveUri: uri => dispatch(doResolveUri(uri)),
});
export default connect(
select,
perform
)(ClaimPreview);

View file

@ -35,7 +35,7 @@ type Props = {
}>,
};
function ClaimListItem(props: Props) {
function ClaimPreview(props: Props) {
const {
obscureNsfw,
claimIsMine,
@ -94,10 +94,10 @@ function ClaimListItem(props: Props) {
if (placeholder && !claim) {
return (
<li className="file-list__item" disabled>
<li className="claim-list__item" disabled>
<div className="placeholder media__thumb" />
<div className="placeholder__wrapper">
<div className="placeholder file-list__item-title" />
<div className="placeholder claim-list__item-title" />
<div className="placeholder media__subtitle" />
</div>
</li>
@ -107,16 +107,17 @@ function ClaimListItem(props: Props) {
return (
<li
role="link"
onClick={onClick}
onClick={pending ? undefined : onClick}
onContextMenu={handleContextMenu}
className={classnames('file-list__item', {
'file-list__item--large': type === 'large',
className={classnames('claim-list__item', {
'claim-list__item--large': type === 'large',
'claim-list__pending': pending,
})}
>
{isChannel ? <ChannelThumbnail uri={uri} /> : <CardMedia thumbnail={thumbnail} />}
<div className="file-list__item-metadata">
<div className="file-list__item-info">
<div className="file-list__item-title">
<div className="claim-list__item-metadata">
<div className="claim-list__item-info">
<div className="claim-list__item-title">
<TruncatedText text={title || (claim && claim.name)} lines={1} />
</div>
{type !== 'small' && (
@ -127,7 +128,7 @@ function ClaimListItem(props: Props) {
)}
</div>
<div className="file-list__item-properties">
<div className="claim-list__item-properties">
<div className="media__subtitle">
<UriIndicator uri={uri} link />
{pending && <div>Pending...</div>}
@ -141,4 +142,4 @@ function ClaimListItem(props: Props) {
);
}
export default withRouter(ClaimListItem);
export default withRouter(ClaimPreview);

View file

@ -1,13 +1,6 @@
// @flow
import * as React from 'react';
// @if TARGET='app'
// $FlowFixMe
import { remote } from 'electron';
// @endif
// @if TARGET='web'
// $FlowFixMe
import { remote } from 'web/stubs';
// @endif
import Button from 'component/button';
import { FormField } from 'component/common/form';
import path from 'path';
@ -21,6 +14,8 @@ type Props = {
type: string,
currentPath: ?string,
onFileChosen: (string, string) => void,
label?: string,
placeholder?: string,
fileLabel?: string,
directoryLabel?: string,
filters?: FileFilters[],
@ -83,13 +78,14 @@ class FileSelector extends React.PureComponent<Props> {
input: ?HTMLInputElement;
render() {
const { type, currentPath, fileLabel, directoryLabel } = this.props;
const { type, currentPath, label, fileLabel, directoryLabel, placeholder } = this.props;
const label = type === 'file' ? fileLabel || __('Choose File') : directoryLabel || __('Choose Directory');
const buttonLabel = type === 'file' ? fileLabel || __('Choose File') : directoryLabel || __('Choose Directory');
return (
<React.Fragment>
<FormField
label={label}
webkitdirectory="true"
className="form-field--copyable"
type="text"
@ -98,8 +94,8 @@ class FileSelector extends React.PureComponent<Props> {
if (this.fileInput) this.fileInput.current.select();
}}
readOnly="readonly"
value={currentPath || __('No File Chosen')}
inputButton={<Button button="primary" label={label} onClick={() => this.handleButtonClick()} />}
value={currentPath || placeholder || __('Choose a file')}
inputButton={<Button button="primary" label={buttonLabel} onClick={() => this.handleButtonClick()} />}
/>
</React.Fragment>
);

View file

@ -1,5 +1,5 @@
// @flow
// A housing for all of our icons. Mostly taken fromhttps://github.com/feathericons/react-feather
// A housing for all of our icons. Mostly taken from https://github.com/feathericons/react-feather
import * as ICONS from 'constants/icons';
import React, { forwardRef } from 'react';
@ -9,7 +9,8 @@ type IconProps = {
};
// Returns a react component
const buildIcon = (iconStrokes: React$Node, options?: {} = {}) =>
// Icons with tooltips need to use this function so the ref can be properly forwarded
const buildIcon = (iconStrokes: React$Node) =>
forwardRef((props: IconProps, ref) => {
const { size = 24, color = 'currentColor', ...otherProps } = props;
return (
@ -24,7 +25,6 @@ const buildIcon = (iconStrokes: React$Node, options?: {} = {}) =>
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...options}
{...otherProps}
>
{iconStrokes}
@ -34,7 +34,7 @@ const buildIcon = (iconStrokes: React$Node, options?: {} = {}) =>
export const icons = {
// The LBRY icon is different from the base icon set so don't use buildIcon()
[ICONS.LBRY]: (
[ICONS.LBRY]: () => (
<svg stroke="currentColor" fill="currentColor" x="0px" y="0px" viewBox="0 0 322 254" className="icon lbry-icon">
<path d="M296,85.9V100l-138.8,85.3L52.6,134l0.2-7.9l104,51.2L289,96.1v-5.8L164.2,30.1L25,116.2v38.5l131.8,65.2 l137.6-84.4l3.9,6l-141.1,86.4L18.1,159.1v-46.8l145.8-90.2C163.9,22.1,296,85.9,296,85.9z" />
<path d="M294.3,150.9l2-12.6l-12.2-2.1l0.8-4.9l17.1,2.9l-2.8,17.5L294.3,150.9L294.3,150.9z" />

View file

@ -13,7 +13,7 @@ const BLUE_COLOR = '#49b2e2';
type Props = {
icon: string,
tooltip?: string, // tooltip direction
tooltip?: boolean,
iconColor?: string,
size?: number,
className?: string,

View file

@ -1,11 +1,12 @@
// @flow
import * as React from 'react';
import type { Node } from 'react';
import React from 'react';
import ReachTooltip from '@reach/tooltip';
import '@reach/tooltip/styles.css';
type Props = {
label: string,
children?: React.Node,
label: string | Node,
children?: Node,
};
function Tooltip(props: Props) {

View file

@ -3,10 +3,12 @@ import Button from 'component/button';
export default function UnsupportedOnWeb() {
return (
<div className="card__content help help--warning">
This page is not currently supported on the web.{' '}
<Button button="link" label={__('Download the desktop app')} href="https://lbry.com/get" /> for full feature
support.
</div>
IS_WEB && (
<div className="card__content help help--warning">
This page is not currently supported on the web.{' '}
<Button button="link" label={__('Download the desktop app')} href="https://lbry.com/get" /> for full feature
support.
</div>
)
);
}

View file

@ -68,7 +68,7 @@ class ErrorBoundary extends React.Component<Props, State> {
render() {
if (this.state.hasError) {
return (
<div className="load-screen">
<div className="main main--empty">
<Yrbl
type="sad"
title={__('Aw shucks!')}

View file

@ -1,7 +1,8 @@
// @flow
import type { Node } from 'react';
import * as MODALS from 'constants/modal_types';
import * as ICONS from 'constants/icons';
import * as React from 'react';
import React from 'react';
import Button from 'component/button';
import Tooltip from 'component/common/tooltip';
import { requestFullscreen, fullscreenElement } from 'util/full-screen';
@ -16,7 +17,7 @@ type Props = {
openModal: (id: string, { uri: string }) => void,
claimIsMine: boolean,
fileInfo: FileInfo,
viewerContainer: React.Ref,
viewerContainer: ?{ current: Node },
showFullscreen: boolean,
};

View file

@ -57,7 +57,7 @@ class FileDownloadLink extends React.PureComponent<Props> {
}
return (
<ToolTip label={__('Download')}>
<ToolTip label={__('Add to your library')}>
<Button
button="link"
icon={ICONS.DOWNLOAD}

View file

@ -23,7 +23,7 @@ export default function FileProperties(props: Props) {
<div className="file-properties">
{isSubscribed && <Icon tooltip icon={icons.SUBSCRIPTION} />}
{!claimIsMine && downloaded && <Icon tooltip icon={icons.DOWNLOAD} />}
{isRewardContent && <Icon tooltip iconColor="red" icon={icons.FEATURED} />}
{isRewardContent && <Icon tooltip icon={icons.FEATURED} />}
<FilePrice hideFree uri={uri} />
</div>
);

View file

@ -4,6 +4,8 @@ import React from 'react';
import LoadingScreen from 'component/common/loading-screen';
import VideoViewer from 'component/viewers/videoViewer';
// Audio player on hold until the current player is dropped
// This component is half working
// const AudioViewer = React.lazy<*>(() =>
// import(/* webpackChunkName: "audioViewer" */
// 'component/viewers/audioViewer')

View file

@ -0,0 +1,46 @@
import { connect } from 'react-redux';
import { doResolveUri, selectBalance } from 'lbry-redux';
import {
selectPublishFormValues,
selectIsStillEditing,
selectMyClaimForUri,
selectIsResolvingPublishUris,
selectTakeOverAmount,
} from 'redux/selectors/publish';
import {
doResetThumbnailStatus,
doClearPublish,
doUpdatePublishForm,
doPublish,
doPrepareEdit,
} from 'redux/actions/publish';
import { selectUnclaimedRewardValue } from 'lbryinc';
import PublishPage from './view';
const select = state => ({
...selectPublishFormValues(state),
// The winning claim for a short lbry uri
amountNeededForTakeover: selectTakeOverAmount(state),
// My previously published claims under this short lbry uri
myClaimForUri: selectMyClaimForUri(state),
// 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: selectIsStillEditing(state),
isResolvingUri: selectIsResolvingPublishUris(state),
totalRewardValue: selectUnclaimedRewardValue(state),
balance: selectBalance(state),
});
const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
clearPublish: () => dispatch(doClearPublish()),
resolveUri: uri => dispatch(doResolveUri(uri)),
publish: params => dispatch(doPublish(params)),
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
});
export default connect(
select,
perform
)(PublishPage);

View file

@ -4,7 +4,7 @@ import { FormField } from 'component/common/form';
import { CC_LICENSES, COPYRIGHT, OTHER, PUBLIC_DOMAIN, NONE } from 'constants/licenses';
type Props = {
licenseType: string,
licenseType: ?string,
licenseUrl: ?string,
otherLicenseDescription: ?string,
handleLicenseChange: (string, string) => void,

View file

@ -0,0 +1,80 @@
// @flow
import React from 'react';
import classnames from 'classnames';
import usePersistedState from 'util/use-persisted-state';
import { FormField } from 'component/common/form';
import Button from 'component/button';
import LicenseType from './license-type';
type Props = {
language: ?string,
name: ?string,
licenseType: ?string,
otherLicenseDescription: ?string,
licenseUrl: ?string,
disabled: boolean,
updatePublishForm: ({}) => void,
};
function PublishAdvanced(props: Props) {
const { language, name, licenseType, otherLicenseDescription, licenseUrl, updatePublishForm } = props;
const [hideSection, setHideSection] = usePersistedState('publish-advanced-options', true);
function toggleHideSection() {
setHideSection(!hideSection);
}
return (
<section className="card card--section">
{!hideSection && (
<div className={classnames('card__content', { 'card--disabled': !name })}>
<FormField
label={__('Language')}
type="select"
name="content_language"
value={language}
onChange={event => updatePublishForm({ language: event.target.value })}
>
<option value="en">{__('English')}</option>
<option value="zh">{__('Chinese')}</option>
<option value="fr">{__('French')}</option>
<option value="de">{__('German')}</option>
<option value="jp">{__('Japanese')}</option>
<option value="ru">{__('Russian')}</option>
<option value="es">{__('Spanish')}</option>
<option value="id">{__('Indonesian')}</option>
<option value="it">{__('Italian')}</option>
<option value="nl">{__('Dutch')}</option>
<option value="tr">{__('Turkish')}</option>
<option value="pl">{__('Polish')}</option>
<option value="ms">{__('Malay')}</option>
</FormField>
<LicenseType
licenseType={licenseType}
otherLicenseDescription={otherLicenseDescription}
licenseUrl={licenseUrl}
handleLicenseChange={(newLicenseType, newLicenseUrl) =>
updatePublishForm({
licenseType: newLicenseType,
licenseUrl: newLicenseUrl,
})
}
handleLicenseDescriptionChange={event =>
updatePublishForm({
otherLicenseDescription: event.target.value,
})
}
handleLicenseUrlChange={event => updatePublishForm({ licenseUrl: event.target.value })}
/>
</div>
)}
<div className="card__actions">
<Button label={hideSection ? __('Additional Options') : __('Hide')} button="link" onClick={toggleHideSection} />
</div>
</section>
);
}
export default PublishAdvanced;

View file

@ -0,0 +1,21 @@
import { connect } from 'react-redux';
import { selectBalance } from 'lbry-redux';
import { selectIsStillEditing, makeSelectPublishFormValue } from 'redux/selectors/publish';
import { doUpdatePublishForm } from 'redux/actions/publish';
import PublishPage from './view';
const select = state => ({
name: makeSelectPublishFormValue('name')(state),
filePath: makeSelectPublishFormValue('filePath')(state),
isStillEditing: selectIsStillEditing(state),
balance: selectBalance(state),
});
const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
});
export default connect(
select,
perform
)(PublishPage);

View file

@ -0,0 +1,54 @@
// @flow
import React from 'react';
import { regexInvalidURI } from 'lbry-redux';
import classnames from 'classnames';
import FileSelector from 'component/common/file-selector';
type Props = {
name: ?string,
filePath: ?string,
isStillEditing: boolean,
balance: number,
updatePublishForm: ({}) => void,
};
function PublishFile(props: Props) {
const { name, balance, filePath, isStillEditing, updatePublishForm } = props;
function handleFileChange(filePath: string, fileName: string) {
const publishFormParams: { filePath: string, name?: string } = { filePath };
if (!name) {
const parsedFileName = fileName.replace(regexInvalidURI, '');
publishFormParams.name = parsedFileName.replace(' ', '-');
}
updatePublishForm(publishFormParams);
}
return (
<section
className={classnames('card card--section', {
'card--disabled': balance === 0,
})}
>
<header className="card__header">
<h2 className="card__title card__title--flex-between">{isStillEditing ? __('Edit') : __('Publish')}</h2>
{isStillEditing && <p className="card__subtitle">{__('You are currently editing a claim.')}</p>}
</header>
<div className="card__content">
<FileSelector currentPath={filePath} onFileChosen={handleFileChange} />
{!!isStillEditing && name && (
<p className="help">
{__("If you don't choose a file, the file from your existing claim")}
{` "${name}" `}
kauffj commented 2019-06-27 22:18:33 +02:00 (Migrated from github.com)
Review

When you notice split i18n strings like this, can you add an annotation of some kind? (I propose //@i18nfixme)

When you notice split i18n strings like this, can you add an annotation of some kind? (I propose `//@i18nfixme`)
{__('will be used.')}
</p>
)}
</div>
</section>
);
}
export default PublishFile;

View file

@ -1,3 +1,45 @@
import PublishForm from './view';
import { connect } from 'react-redux';
import { doResolveUri } from 'lbry-redux';
import {
selectPublishFormValues,
selectIsStillEditing,
selectMyClaimForUri,
selectIsResolvingPublishUris,
selectTakeOverAmount,
} from 'redux/selectors/publish';
import {
doResetThumbnailStatus,
doClearPublish,
doUpdatePublishForm,
doPublish,
doPrepareEdit,
} from 'redux/actions/publish';
import { selectUnclaimedRewardValue } from 'lbryinc';
import PublishPage from './view';
export default PublishForm;
const select = state => ({
...selectPublishFormValues(state),
// The winning claim for a short lbry uri
amountNeededForTakeover: selectTakeOverAmount(state),
// My previously published claims under this short lbry uri
myClaimForUri: selectMyClaimForUri(state),
// 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: selectIsStillEditing(state),
isResolvingUri: selectIsResolvingPublishUris(state),
totalRewardValue: selectUnclaimedRewardValue(state),
});
const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
clearPublish: () => dispatch(doClearPublish()),
resolveUri: uri => dispatch(doResolveUri(uri)),
publish: params => dispatch(doPublish(params)),
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
});
export default connect(
select,
perform
)(PublishPage);

View file

@ -1,38 +0,0 @@
// @flow
import * as React from 'react';
type Props = {
uri: ?string,
isResolvingUri: boolean,
amountNeededForTakeover: ?number,
};
class BidHelpText extends React.PureComponent<Props> {
render() {
const { uri, isResolvingUri, amountNeededForTakeover } = this.props;
let bidHelpText;
if (uri) {
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 someone navigates to'
)} ${uri} ${__('it will load your published content')}. ${__(
'However, you can get a longer version of this URL for any bid'
)}.`;
}
}
return (
<React.Fragment>
{__('This LBC remains yours and the deposit can be undone at any time.')}
<div>{bidHelpText}</div>
</React.Fragment>
);
}
}
export default BidHelpText;

View file

@ -1,50 +0,0 @@
// @flow
import * as React from 'react';
import Button from 'component/button';
import { buildURI } from 'lbry-redux';
type Props = {
uri: ?string,
myClaimForUri: ?StreamClaim,
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 || (
<span>{__('Create a URL for this content. Simpler names are easier to find and remember.')}</span>
)}
</React.Fragment>
);
}
}
export default NameHelpText;

View file

@ -1,21 +1,22 @@
// @flow
import { COPYRIGHT, OTHER } from 'constants/licenses';
import { CHANNEL_NEW, CHANNEL_ANONYMOUS, MINIMUM_PUBLISH_BID } from 'constants/claim';
import * as ICONS from 'constants/icons';
import * as React from 'react';
import { isNameValid, buildURI, regexInvalidURI, THUMBNAIL_STATUSES } from 'lbry-redux';
import { Form, FormField, FormFieldPrice, Submit } from 'component/common/form';
import React, { useEffect, Fragment } from 'react';
import { CHANNEL_NEW, CHANNEL_ANONYMOUS } from 'constants/claim';
import { buildURI, THUMBNAIL_STATUSES } from 'lbry-redux';
import Button from 'component/button';
import ChannelSection from 'component/selectChannel';
import classnames from 'classnames';
import FileSelector from 'component/common/file-selector';
import SelectThumbnail from 'component/selectThumbnail';
import UnsupportedOnWeb from 'component/common/unsupported-on-web';
import BidHelpText from './internal/bid-help-text';
import NameHelpText from './internal/name-help-text';
import LicenseType from './internal/license-type';
import TagSelect from 'component/tagsSelect';
import PublishText from 'component/publishText';
import PublishPrice from 'component/publishPrice';
import PublishFile from 'component/publishFile';
import PublishName from 'component/publishName';
import PublishAdditionalOptions from 'component/publishAdditionalOptions';
import PublishFormErrors from 'component/publishFormErrors';
import SelectThumbnail from 'component/selectThumbnail';
type Props = {
tags: Array<Tag>,
publish: PublishParams => void,
filePath: ?string,
bid: ?number,
@ -34,7 +35,6 @@ type Props = {
},
channel: string,
name: ?string,
updatePublishForm: UpdatePublishFormData => void,
nameError: ?string,
isResolvingUri: boolean,
winningBidForClaimUri: number,
@ -43,7 +43,6 @@ type Props = {
otherLicenseDescription: ?string,
licenseUrl: ?string,
uri: ?string,
bidError: ?string,
publishing: boolean,
balance: number,
isStillEditing: boolean,
@ -53,35 +52,49 @@ type Props = {
prepareEdit: (claim: any, uri: string) => void,
resetThumbnailStatus: () => void,
amountNeededForTakeover: ?number,
// Add back type
updatePublishForm: any => void,
};
class PublishForm extends React.PureComponent<Props> {
constructor(props: Props) {
super(props);
function PublishForm(props: Props) {
const {
thumbnail,
name,
channel,
editingURI,
resolveUri,
title,
bid,
uploadThumbnailStatus,
resetThumbnailStatus,
updatePublishForm,
filePath,
publishing,
clearPublish,
isStillEditing,
tags,
publish,
} = props;
const formDisabled = (!filePath && !editingURI) || publishing;
// If they are editing, they don't need a new file chosen
const formValidLessFile = name && title && bid && !(uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS);
const formValid = editingURI && !filePath ? isStillEditing && formValidLessFile : formValidLessFile;
(this: any).handleFileChange = this.handleFileChange.bind(this);
(this: any).checkIsFormValid = this.checkIsFormValid.bind(this);
(this: any).renderFormErrors = this.renderFormErrors.bind(this);
(this: any).handlePublish = this.handlePublish.bind(this);
(this: any).handleCancelPublish = this.handleCancelPublish.bind(this);
(this: any).handleNameChange = this.handleNameChange.bind(this);
(this: any).handleChannelChange = this.handleChannelChange.bind(this);
(this: any).editExistingClaim = this.editExistingClaim.bind(this);
(this: any).getNewUri = this.getNewUri.bind(this);
let submitLabel;
if (isStillEditing) {
submitLabel = !publishing ? __('Edit') : __('Editing...');
} else {
submitLabel = !publishing ? __('Publish') : __('Publishing...');
}
componentDidMount() {
const { thumbnail, name, channel, editingURI } = this.props;
useEffect(() => {
if (!thumbnail) {
this.props.resetThumbnailStatus();
resetThumbnailStatus();
}
if (editingURI) {
this.getNewUri(name, channel);
}
}
}, [thumbnail, resetThumbnailStatus]);
getNewUri(name: string, channel: string) {
const { resolveUri } = this.props;
// Every time the channel or name changes, resolve the uris to find winning bid amounts
useEffect(() => {
// If they are midway through a channel creation, treat it as anonymous until it completes
const channelName = channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW ? '' : channel;
@ -89,523 +102,78 @@ class PublishForm extends React.PureComponent<Props> {
let uri;
try {
uri = buildURI({ contentName: name, channelName });
} catch (e) {
// something wrong with channel or name
} catch (e) {}
if (channelName) {
// resolve without the channel name so we know the winning bid for it
const uriLessChannel = buildURI({ contentName: name });
resolveUri(uriLessChannel);
}
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);
return uri;
updatePublishForm({ uri });
}
}, [name, channel, resolveUri, updatePublishForm]);
return '';
}
return (
<Fragment>
<UnsupportedOnWeb />
handleFileChange(filePath: string, fileName: string) {
const { updatePublishForm, channel, name } = this.props;
const newFileParams: UpdatePublishFormData = { filePath };
if (!name) {
const parsedFileName = fileName.replace(regexInvalidURI, '');
const uri = this.getNewUri(parsedFileName, channel);
newFileParams.name = parsedFileName;
newFileParams.uri = uri;
}
updatePublishForm(newFileParams);
}
handleNameChange(name: ?string) {
const { channel, updatePublishForm } = this.props;
if (!name) {
updatePublishForm({ name: '', nameError: __('A name is required.') });
return;
}
if (!isNameValid(name, false)) {
updatePublishForm({
name,
nameError: __('LBRY names must contain only letters, numbers and dashes.'),
});
return;
}
const uri = this.getNewUri(name, channel);
updatePublishForm({
name,
uri,
nameError: undefined,
});
}
handleChannelChange(channelName: string) {
const { name, updatePublishForm } = this.props;
const form: UpdatePublishFormData = { channel: channelName };
if (name) {
form.uri = this.getNewUri(name, channelName);
}
updatePublishForm(form);
}
handleBidChange(bid: number) {
const { balance, updatePublishForm, myClaimForUri } = this.props;
let previousBidAmount = 0;
if (myClaimForUri) {
previousBidAmount = Number(myClaimForUri.amount);
}
const totalAvailableBidAmount = previousBidAmount + balance;
let bidError;
if (bid === 0) {
bidError = __('Deposit cannot be 0');
} else if (totalAvailableBidAmount === bid) {
bidError = __('Please decrease your deposit to account for transaction fees');
} else if (totalAvailableBidAmount < bid) {
bidError = __('Deposit cannot be higher than your balance');
} else if (bid <= MINIMUM_PUBLISH_BID) {
bidError = __('Your deposit must be higher');
}
updatePublishForm({ bid, bidError });
}
editExistingClaim(myClaimForUri: ?{}, uri: string) {
const { prepareEdit, scrollToTop } = this.props;
if (myClaimForUri) {
prepareEdit(myClaimForUri, uri);
scrollToTop();
}
}
handleCancelPublish() {
const { clearPublish, scrollToTop } = this.props;
scrollToTop();
clearPublish();
}
handlePublish() {
const { filePath, licenseType, licenseUrl, otherLicenseDescription, publish } = this.props;
let publishingLicense;
switch (licenseType) {
case COPYRIGHT:
case OTHER:
publishingLicense = otherLicenseDescription;
break;
default:
publishingLicense = licenseType;
}
const publishingLicenseUrl = licenseType === COPYRIGHT ? '' : licenseUrl;
const publishParams: PublishParams = {
filePath: filePath || undefined,
bid: this.props.bid || undefined,
title: this.props.title || '',
thumbnail: this.props.thumbnail,
description: this.props.description,
language: this.props.language,
nsfw: this.props.nsfw,
license: publishingLicense,
licenseUrl: publishingLicenseUrl,
otherLicenseDescription,
name: this.props.name || undefined,
contentIsFree: this.props.contentIsFree,
fee: this.props.fee,
uri: this.props.uri || undefined,
channel: this.props.channel,
isStillEditing: this.props.isStillEditing,
claim: this.props.myClaimForUri,
};
publish(publishParams);
}
checkIsFormValid() {
const {
name,
nameError,
title,
bid,
bidError,
editingURI,
isStillEditing,
filePath,
uploadThumbnailStatus,
} = this.props;
// If they are editing, they don't need a new file chosen
const formValidLessFile =
name && !nameError && title && bid && !bidError && !(uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS);
return editingURI && !filePath ? isStillEditing && formValidLessFile : formValidLessFile;
}
renderFormErrors() {
const {
name,
nameError,
title,
bid,
bidError,
editingURI,
filePath,
isStillEditing,
uploadThumbnailStatus,
} = this.props;
const isFormValid = this.checkIsFormValid();
// These are extra help
// If there is an error it will be presented as an inline error as well
return (
!isFormValid && (
<div className="card__content error-text">
{!title && <div>{__('A title is required')}</div>}
{!name && <div>{__('A URL is required')}</div>}
{name && nameError && <div>{__('The URL you created is not valid')}</div>}
{!bid && <div>{__('A deposit amount is required')}</div>}
{!!bid && bidError && <div>{bidError}</div>}
{uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS && (
<div>{__('Please wait for thumbnail to finish uploading')}</div>
)}
{!!editingURI && !isStillEditing && !filePath && (
<div>{__('You need to reselect a file after changing the LBRY URL')}</div>
)}
<PublishFile />
<div className={classnames({ 'card--disabled': formDisabled })}>
<PublishText disabled={formDisabled} />
<div className="card card--section">
{/* This should probably be PublishThumbnail */}
<SelectThumbnail />
</div>
)
);
}
render() {
const {
filePath,
editingURI,
title,
thumbnail,
uploadThumbnailStatus,
description,
language,
nsfw,
contentIsFree,
fee,
channel,
name,
updatePublishForm,
bid,
nameError,
isResolvingUri,
winningBidForClaimUri,
myClaimForUri,
licenseType,
otherLicenseDescription,
licenseUrl,
uri,
bidError,
publishing,
clearPublish,
thumbnailPath,
resetThumbnailStatus,
isStillEditing,
amountNeededForTakeover,
balance,
} = this.props;
const formDisabled = (!filePath && !editingURI) || publishing;
const formValid = this.checkIsFormValid();
let submitLabel;
if (isStillEditing) {
submitLabel = !publishing ? __('Edit') : __('Editing...');
} else {
submitLabel = !publishing ? __('Publish') : __('Publishing...');
}
const shortUri = buildURI({ contentName: name });
return (
<React.Fragment>
{IS_WEB && <UnsupportedOnWeb />}
<Form onSubmit={this.handlePublish}>
<section
className={classnames('card card--section', {
'card--disabled': IS_WEB || publishing || balance === 0,
})}
>
<header className="card__header">
<h2 className="card__title card__title--flex-between">
{__('Content')}
{(filePath || !!editingURI) && (
<Button button="inverse" icon={ICONS.REMOVE} label={__('Clear')} onClick={clearPublish} />
)}
</h2>
<p className="card__subtitle">
{isStillEditing ? __('You are currently editing a claim.') : __('What are you publishing?')}{' '}
{__('Read our')} <Button button="link" label={__('FAQ')} href="https://lbry.com/faq/how-to-publish" />{' '}
{__('to learn more.')}
</p>
</header>
<div className="card__content">
<FileSelector currentPath={filePath} onFileChosen={this.handleFileChange} />
{!!isStillEditing && name && (
<p className="help">
{__("If you don't choose a file, the file from your existing claim")}
{` "${name}" `}
{__('will be used.')}
</p>
)}
</div>
</section>
<div className={classnames({ 'card--disabled': formDisabled })}>
<section className="card card--section">
<div className="card__content">
<FormField
type="text"
name="content_title"
label={__('Title')}
placeholder={__('Titular Title')}
disabled={formDisabled}
value={title}
onChange={e => updatePublishForm({ title: e.target.value })}
/>
<FormField
type="markdown"
name="content_description"
label={__('Description')}
placeholder={__('Description of your content')}
value={description}
disabled={formDisabled}
onChange={text => updatePublishForm({ description: text })}
/>
</div>
</section>
<section className="card card--section">
<header className="card__header">
<h2 className="card__title">{__('Thumbnail')}</h2>
<p className="card__subtitle">
{(uploadThumbnailStatus === undefined && __('You should reselect your file to choose a thumbnail')) ||
(uploadThumbnailStatus === THUMBNAIL_STATUSES.API_DOWN ? (
__('Enter a URL for your thumbnail.')
) : (
<React.Fragment>
{__('Upload your thumbnail (.png/.jpg/.jpeg/.gif) to')}{' '}
<Button button="link" label={__('spee.ch')} href="https://spee.ch/about" />.{' '}
{__('Recommended size: 800x450 (16:9)')}
</React.Fragment>
))}
</p>
</header>
<SelectThumbnail
filePath={filePath}
thumbnailPath={thumbnailPath}
thumbnail={thumbnail}
uploadThumbnailStatus={uploadThumbnailStatus}
updatePublishForm={updatePublishForm}
formDisabled={formDisabled}
resetThumbnailStatus={resetThumbnailStatus}
/>
</section>
<section className="card card--section">
<header className="card__header">
<h2 className="card__title">{__('Price')}</h2>
<p className="card__subtitle">{__('How much will this content cost?')}</p>
</header>
<div className="card__content">
<FormField
type="radio"
name="content_free"
label={__('Free')}
checked={contentIsFree}
disabled={formDisabled}
onChange={() => updatePublishForm({ contentIsFree: true })}
/>
<FormField
type="radio"
name="content_cost"
label={__('Choose price')}
checked={!contentIsFree}
disabled={formDisabled}
onChange={() => updatePublishForm({ contentIsFree: false })}
/>
{!contentIsFree && (
<FormFieldPrice
name="content_cost_amount"
min="0"
price={fee}
onChange={newFee => updatePublishForm({ fee: newFee })}
/>
)}
{fee && fee.currency !== 'LBC' && (
<p className="form-field__help">
{__(
'All content fees are charged in LBC. For non-LBC payment methods, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase.'
)}
</p>
)}
</div>
</section>
<section className="card card--section">
<header className="card__header">
<h2 className="card__title">{__('Anonymous or under a channel?')}</h2>
<p className="card__subtitle">
{__('This is a username or handle that your content can be found under.')}{' '}
{__('Ex. @Marvel, @TheBeatles, @BooksByJoe')}
</p>
</header>
<div className="card__content">
<ChannelSection channel={channel} onChannelChange={this.handleChannelChange} />
</div>
</section>
<section className="card card--section">
<header className="card__header">
<h2 className="card__title">{__('Where can people find this content?')}</h2>
<p className="card__subtitle">
{__('The LBRY URL is the exact address where people find your content (ex. lbry://myvideo).')}{' '}
<Button button="link" label={__('Learn more')} href="https://lbry.com/faq/naming" />
</p>
</header>
<div className="card__content">
<fieldset-group class="fieldset-group--smushed fieldset-group--disabled-prefix">
<fieldset-section>
<label>{__('Name')}</label>
<span className="form-field__prefix">{`lbry://${
!channel || channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW ? '' : `${channel}/`
}`}</span>
</fieldset-section>
<FormField
type="text"
name="content_name"
value={name}
onChange={event => this.handleNameChange(event.target.value)}
error={nameError}
/>
</fieldset-group>
<div className="form-field__help">
<NameHelpText
isStillEditing={isStillEditing}
uri={uri}
myClaimForUri={myClaimForUri}
onEditMyClaim={this.editExistingClaim}
/>
</div>
</div>
<div className={classnames('card__content', { 'card--disabled': !name })}>
<FormField
className="form-field--price-amount"
type="number"
name="content_bid"
step="any"
label={__('Deposit (LBC)')}
postfix="LBC"
value={bid}
error={bidError}
min="0"
disabled={!name}
onChange={event => this.handleBidChange(parseFloat(event.target.value))}
placeholder={winningBidForClaimUri ? winningBidForClaimUri + 0.1 : 0.1}
helper={
<BidHelpText
uri={shortUri}
isResolvingUri={isResolvingUri}
amountNeededForTakeover={amountNeededForTakeover}
/>
}
/>
</div>
</section>
<section className="card card--section">
<div className="card__content">
<FormField
type="checkbox"
name="content_is_mature"
label={__('Mature audiences only')}
checked={nsfw}
onChange={() => updatePublishForm({ nsfw: !nsfw })}
/>
<FormField
label={__('Language')}
type="select"
name="content_language"
value={language}
onChange={event => updatePublishForm({ language: event.target.value })}
>
<option value="en">{__('English')}</option>
<option value="zh">{__('Chinese')}</option>
<option value="fr">{__('French')}</option>
<option value="de">{__('German')}</option>
<option value="jp">{__('Japanese')}</option>
<option value="ru">{__('Russian')}</option>
<option value="es">{__('Spanish')}</option>
<option value="id">{__('Indonesian')}</option>
<option value="it">{__('Italian')}</option>
<option value="nl">{__('Dutch')}</option>
<option value="tr">{__('Turkish')}</option>
<option value="pl">{__('Polish')}</option>
<option value="ms">{__('Malay')}</option>
</FormField>
<LicenseType
licenseType={licenseType}
otherLicenseDescription={otherLicenseDescription}
licenseUrl={licenseUrl}
handleLicenseChange={(newLicenseType, newLicenseUrl) =>
updatePublishForm({
licenseType: newLicenseType,
licenseUrl: newLicenseUrl,
})
}
handleLicenseDescriptionChange={event =>
updatePublishForm({
otherLicenseDescription: event.target.value,
})
}
handleLicenseUrlChange={event => updatePublishForm({ licenseUrl: event.target.value })}
/>
</div>
</section>
<section className="card card--section">
<div className="card__actions">
<Submit
label={submitLabel}
disabled={formDisabled || !formValid || uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS}
/>
<Button button="link" onClick={this.handleCancelPublish} label={__('Cancel')} />
</div>
<p className="help">
{__('By continuing, you accept the')}{' '}
<Button button="link" href="https://www.lbry.com/termsofservice" label={__('LBRY Terms of Service')} />.
</p>
</section>
<div className="card">
<TagSelect
title={false}
help={__('The better your tags are, the easier it will be for people to discover your content.')}
empty={__('No tags added')}
onSelect={tag => updatePublishForm({ tags: [...tags, tag] })}
onRemove={clickedTag => {
const newTags = tags.slice().filter(tag => tag.name !== clickedTag.name);
updatePublishForm({ tags: newTags });
}}
tagsChosen={tags}
/>
</div>
<section className="card card--section">
<div className="card__content">
<ChannelSection channel={channel} onChannelChange={channel => updatePublishForm({ channel })} />
<p className="help">
{__('This is a username or handle that your content can be found under.')}{' '}
{__('Ex. @Marvel, @TheBeatles, @BooksByJoe')}
</p>
</div>
</section>
{!formDisabled && !formValid && this.renderFormErrors()}
</Form>
</React.Fragment>
);
}
<PublishName disabled={formDisabled} />
<PublishPrice disabled={formDisabled} />
<PublishAdditionalOptions disabled={formDisabled} />
<section className="card card--section">
{!formDisabled && !formValid && <PublishFormErrors />}
<div className="card__actions">
<Button
button="primary"
onClick={publish}
label={submitLabel}
disabled={formDisabled || !formValid || uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS}
/>
<Button button="link" onClick={clearPublish} label={__('Cancel')} />
</div>
<p className="help">
{__('By continuing, you accept the')}{' '}
<Button button="link" href="https://www.lbry.com/termsofservice" label={__('LBRY Terms of Service')} />.
</p>
</section>
</div>
</Fragment>
);
}
export default PublishForm;

View file

@ -0,0 +1,17 @@
import { connect } from 'react-redux';
import { makeSelectPublishFormValue, selectIsStillEditing } from 'redux/selectors/publish';
import PublishPage from './view';
const select = state => ({
name: makeSelectPublishFormValue('name')(state),
title: makeSelectPublishFormValue('title')(state),
bid: makeSelectPublishFormValue('bid')(state),
editingUri: makeSelectPublishFormValue('editingUri')(state),
uploadThumbnailStatus: makeSelectPublishFormValue('uploadThumbnailStatus')(state),
isStillEditing: selectIsStillEditing(state),
});
export default connect(
select,
null
)(PublishPage);

View file

@ -0,0 +1,35 @@
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
// @flow
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
import React from 'react';
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
import { THUMBNAIL_STATUSES } from 'lbry-redux';
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
type Props = {
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
title: ?string,
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
name: ?string,
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
bid: ?string,
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
editingURI: ?string,
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
filePath: ?string,
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
isStillEditing: boolean,
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
uploadThumbnailStatus: string,
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
};
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
function PublishFormErrors(props: Props) {
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
const { name, title, bid, editingURI, filePath, isStillEditing, uploadThumbnailStatus } = props;
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
// These are extra help
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
// If there is an error it will be presented as an inline error as well
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
return (
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
<div className="card__content error-text">
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
{!title && <div>{__('A title is required')}</div>}
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
{!name && <div>{__('A URL is required')}</div>}
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
{!bid && <div>{__('A deposit amount is required')}</div>}
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
{uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS && (
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
<div>{__('Please wait for thumbnail to finish uploading')}</div>
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
)}
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
{!!editingURI && !isStillEditing && !filePath && (
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
<div>{__('You need to reselect a file after changing the LBRY URL')}</div>
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
)}
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
</div>
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
);
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
}
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.
export default PublishFormErrors;
kauffj commented 2019-06-27 22:20:06 +02:00 (Migrated from github.com)
Review

Can this be re-written to say "Please"?

(also, why is this necessary?)

Can this be re-written to say "Please"? (also, why is this necessary?)
neb-b commented 2019-06-28 09:07:42 +02:00 (Migrated from github.com)
Review

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

It shouldn't be, but we aren't currently tracking the previous claim, after you change the name, because that could be another claim.

View file

@ -0,0 +1,32 @@
// @flow
type Props = {
uri: ?string,
isResolvingUri: boolean,
amountNeededForTakeover: number,
};
function BidHelpText(props: Props) {
const { uri, isResolvingUri, amountNeededForTakeover } = props;
let bidHelpText;
if (uri) {
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 someone navigates to'
kauffj commented 2019-06-27 22:20:55 +02:00 (Migrated from github.com)
Review

@i18nfixme

(also, these split strings are basically not worth even calling the function on, but should be tagged either way)

`@i18nfixme` (also, these split strings are basically not worth even calling the function on, but should be tagged either way)
)} ${uri} ${__('it will load your published content')}. ${__(
'However, you can get a longer version of this URL for any bid'
)}.`;
}
} else {
bidHelpText = __('This LBC remains yours and the deposit can be undone at any time.');
}
return bidHelpText;
}
export default BidHelpText;

View file

@ -0,0 +1,32 @@
import { connect } from 'react-redux';
import {
makeSelectPublishFormValue,
selectIsStillEditing,
selectMyClaimForUri,
selectIsResolvingPublishUris,
selectTakeOverAmount,
} from 'redux/selectors/publish';
import { doUpdatePublishForm, doPrepareEdit } from 'redux/actions/publish';
import { selectBalance } from 'lbry-redux';
import PublishPage from './view';
const select = state => ({
name: makeSelectPublishFormValue('name')(state),
channel: makeSelectPublishFormValue('channel')(state),
uri: makeSelectPublishFormValue('uri')(state),
isStillEditing: selectIsStillEditing(state),
isResolvingUri: selectIsResolvingPublishUris(state),
amountNeededForTakeover: selectTakeOverAmount(state),
balance: selectBalance(state),
myClaimForUri: selectMyClaimForUri(state),
});
const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
});
export default connect(
select,
perform
)(PublishPage);

View file

@ -0,0 +1,46 @@
// @flow
import * as React from 'react';
import Button from 'component/button';
import { buildURI } from 'lbry-redux';
type Props = {
uri: ?string,
myClaimForUri: ?StreamClaim,
isStillEditing: boolean,
onEditMyClaim: (any, string) => void,
};
function NameHelpText(props: Props) {
const { uri, myClaimForUri, onEditMyClaim, isStillEditing } = 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 || (
<span>{__('Create a URL for this content. Simpler names are easier to find and remember.')}</span>
)}
</React.Fragment>
);
}
export default NameHelpText;

View file

@ -0,0 +1,124 @@
// @flow
import { CHANNEL_NEW, CHANNEL_ANONYMOUS, MINIMUM_PUBLISH_BID } from 'constants/claim';
import React, { useState, useEffect } from 'react';
import { isNameValid } from 'lbry-redux';
import { FormField } from 'component/common/form';
import NameHelpText from './name-help-text';
import BidHelpText from './bid-help-text';
type Props = {
name: string,
channel: string,
uri: string,
bid: string,
balance: number,
isStillEditing: boolean,
myClaimForUri: ?StreamClaim,
isResolvingUri: boolean,
amountNeededForTakeover: number,
prepareEdit: ({}, string) => void,
updatePublishForm: ({}) => void,
};
function PublishText(props: Props) {
const {
name,
channel,
uri,
isStillEditing,
myClaimForUri,
bid: bidString,
isResolvingUri,
amountNeededForTakeover,
prepareEdit,
updatePublishForm,
balance,
} = props;
const [nameError, setNameError] = useState(undefined);
const [bidError, setBidError] = useState(undefined);
const previousBidAmount = myClaimForUri && Number(myClaimForUri.amount);
const bid = Number(bidString);
function editExistingClaim() {
if (myClaimForUri) {
prepareEdit(myClaimForUri, uri);
}
}
useEffect(() => {
let nameError;
if (!name) {
nameError = __('A name is required');
} else if (!isNameValid(name, false)) {
nameError = __('LBRY names cannot contain that symbol ($, #, @)');
kauffj commented 2019-06-27 22:22:36 +02:00 (Migrated from github.com)
Review

Some symbols are missing here. It's probably worth adding a RESERVED_CHARACTER const to lbryUri.js.

Some symbols are missing here. It's probably worth adding a `RESERVED_CHARACTER` const to `lbryUri.js`.
}
setNameError(nameError);
}, [name]);
useEffect(() => {
const totalAvailableBidAmount = previousBidAmount + balance;
let bidError;
if (bid === 0) {
bidError = __('Deposit cannot be 0');
} else if (totalAvailableBidAmount === bid) {
bidError = __('Please decrease your deposit to account for transaction fees');
} else if (totalAvailableBidAmount < bid) {
bidError = __('Deposit cannot be higher than your balance');
} else if (bid <= MINIMUM_PUBLISH_BID) {
bidError = __('Your deposit must be higher');
}
setBidError(bidError);
}, [bid, previousBidAmount, balance]);
return (
<section className="card card--section">
<div className="card__content">
<fieldset-group class="fieldset-group--smushed fieldset-group--disabled-prefix">
<fieldset-section>
<label>{__('Name')}</label>
<span className="form-field__prefix">{`lbry://${
!channel || channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW ? '' : `${channel}/`
}`}</span>
</fieldset-section>
<FormField
type="text"
name="content_name"
value={name}
error={nameError}
onChange={event => updatePublishForm({ name: event.target.value })}
/>
</fieldset-group>
<div className="form-field__help">
<NameHelpText
uri={uri}
isStillEditing={isStillEditing}
myClaimForUri={myClaimForUri}
onEditMyClaim={editExistingClaim}
/>
</div>
</div>
<FormField
type="number"
name="content_bid"
min="0"
step="any"
placeholder="0.123"
className="form-field--price-amount"
label={__('Deposit (LBC)')}
postfix="LBC"
value={bid}
error={bidError}
disabled={!name}
onChange={event => updatePublishForm({ bid: parseFloat(event.target.value) })}
helper={
<BidHelpText uri={uri} amountNeededForTakeover={amountNeededForTakeover} isResolvingUri={isResolvingUri} />
}
/>
</section>
);
}
export default PublishText;

View file

@ -0,0 +1,46 @@
import { connect } from 'react-redux';
import { doResolveUri, selectBalance } from 'lbry-redux';
import {
selectPublishFormValues,
selectIsStillEditing,
selectMyClaimForUri,
selectIsResolvingPublishUris,
selectTakeOverAmount,
} from 'redux/selectors/publish';
import {
doResetThumbnailStatus,
doClearPublish,
doUpdatePublishForm,
doPublish,
doPrepareEdit,
} from 'redux/actions/publish';
import { selectUnclaimedRewardValue } from 'lbryinc';
import PublishPage from './view';
const select = state => ({
...selectPublishFormValues(state),
// The winning claim for a short lbry uri
amountNeededForTakeover: selectTakeOverAmount(state),
// My previously published claims under this short lbry uri
myClaimForUri: selectMyClaimForUri(state),
// 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: selectIsStillEditing(state),
balance: selectBalance(state),
isResolvingUri: selectIsResolvingPublishUris(state),
totalRewardValue: selectUnclaimedRewardValue(state),
});
const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
clearPublish: () => dispatch(doClearPublish()),
resolveUri: uri => dispatch(doResolveUri(uri)),
publish: params => dispatch(doPublish(params)),
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
});
export default connect(
select,
perform
)(PublishPage);

View file

@ -0,0 +1,55 @@
// @flow
import React from 'react';
import { FormField, FormFieldPrice } from 'component/common/form';
type Props = {
contentIsFree: boolean,
fee: Fee,
disabled: boolean,
updatePublishForm: ({}) => void,
};
function PublishText(props: Props) {
const { contentIsFree, fee, updatePublishForm, disabled } = props;
return (
<section className="card card--section">
<div className="card__content">
<FormField
type="radio"
name="content_free"
label={__('Free')}
checked={contentIsFree}
disabled={disabled}
onChange={() => updatePublishForm({ contentIsFree: true })}
/>
<FormField
type="radio"
name="content_cost"
label={__('Add a price to this file')}
checked={!contentIsFree}
disabled={disabled}
onChange={() => updatePublishForm({ contentIsFree: false })}
/>
{!contentIsFree && (
<FormFieldPrice
name="content_cost_amount"
min="0"
price={fee}
onChange={newFee => updatePublishForm({ fee: newFee })}
/>
)}
{fee && fee.currency !== 'LBC' && (
<p className="form-field__help">
{__(
'All content fees are charged in LBC. For non-LBC payment methods, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase.'
)}
</p>
)}
</div>
</section>
);
}
export default PublishText;

View file

@ -0,0 +1,18 @@
import { connect } from 'react-redux';
import { makeSelectPublishFormValue } from 'redux/selectors/publish';
import { doUpdatePublishForm } from 'redux/actions/publish';
import PublishPage from './view';
const select = state => ({
title: makeSelectPublishFormValue('title')(state),
description: makeSelectPublishFormValue('description')(state),
});
const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
});
export default connect(
select,
perform
)(PublishPage);

View file

@ -0,0 +1,51 @@
// @flow
import React from 'react';
import { FormField } from 'component/common/form';
import Button from 'component/button';
import usePersistedState from 'util/use-persisted-state';
type Props = {
title: ?string,
description: ?string,
disabled: boolean,
updatePublishForm: ({}) => void,
};
function PublishText(props: Props) {
const { title, description, updatePublishForm, disabled } = props;
const [advancedEditor, setAdvancedEditor] = usePersistedState('publish-form-description-mode', false);
function toggleMarkdown() {
setAdvancedEditor(!advancedEditor);
}
return (
<section className="card card--section">
<div className="card__content">
<FormField
type="text"
name="content_title"
label={__('Title')}
placeholder={__('Titular Title')}
disabled={disabled}
value={title}
onChange={e => updatePublishForm({ title: e.target.value })}
/>
<FormField
type={advancedEditor ? 'markdown' : 'textarea'}
name="content_description"
label={__('Description')}
placeholder={__('My description for this and that')}
value={description}
disabled={disabled}
onChange={value => updatePublishForm({ description: advancedEditor ? value : value.target.text })}
/>
<div className="card__actions">
<Button button="link" onClick={toggleMarkdown} label={advancedEditor ? 'Simple Editor' : 'Advanced Editor'} />
</div>
</div>
</section>
);
}
export default PublishText;

View file

@ -20,7 +20,7 @@ import UserHistoryPage from 'page/userHistory';
import WalletPage from 'page/wallet';
import NavigationHistory from 'page/navigationHistory';
import TagsPage from 'page/tags';
import TagsEditPage from 'page/tagsEdit';
import FollowingPage from 'page/following';
const Scroll = withRouter(function ScrollWrapper(props) {
const { pathname } = props.location;
@ -50,17 +50,17 @@ export default function AppRouter() {
<Route path={`/$/${PAGES.REWARDS}`} exact component={RewardsPage} />
<Route path={`/$/${PAGES.SEARCH}`} exact component={SearchPage} />
<Route path={`/$/${PAGES.SETTINGS}`} exact component={SettingsPage} />
<Route path={`/$/${PAGES.SUBSCRIPTIONS}`} exact component={SubscriptionsPage} />
<Route path={`/$/${PAGES.TRANSACTIONS}`} exact component={TransactionHistoryPage} />
<Route path={`/$/${PAGES.LIBRARY}`} exact component={UserHistoryPage} />
<Route path={`/$/${PAGES.ACCOUNT}`} exact component={AccountPage} />
<Route path={`/$/${PAGES.LIBRARY}/all`} exact component={NavigationHistory} />
<Route path={`/$/${PAGES.TAGS}`} exact component={TagsPage} />
<Route path={`/$/${PAGES.TAGS}/edit`} exact component={TagsEditPage} />
<Route path={`/$/${PAGES.FOLLOWING}`} exact component={SubscriptionsPage} />
<Route path={`/$/${PAGES.FOLLOWING}/edit`} exact component={FollowingPage} />
<Route path={`/$/${PAGES.WALLET}`} exact component={WalletPage} />
{/* Below need to go at the end to make sure we don't match any of our pages first */}
<Route path="/:claimName" exact component={ShowPage} />
<Route path="/:claimName/:claimId" exact component={ShowPage} />
<Route path="/:claimName/:contentName" exact component={ShowPage} />
{/* Route not found. Mostly for people typing crazy urls into the url */}
<Route render={() => <Redirect to="/" />} />

View file

@ -1,12 +1,47 @@
import { connect } from 'react-redux';
import { doResolveUri } from 'lbry-redux';
import {
selectPublishFormValues,
selectIsStillEditing,
selectMyClaimForUri,
selectIsResolvingPublishUris,
selectTakeOverAmount,
} from 'redux/selectors/publish';
import {
doResetThumbnailStatus,
doClearPublish,
doUpdatePublishForm,
doPublish,
doPrepareEdit,
} from 'redux/actions/publish';
import { doOpenModal } from 'redux/actions/app';
import SelectThumbnail from './view';
import { selectUnclaimedRewardValue } from 'lbryinc';
import PublishPage from './view';
const select = state => ({
...selectPublishFormValues(state),
// The winning claim for a short lbry uri
amountNeededForTakeover: selectTakeOverAmount(state),
// My previously published claims under this short lbry uri
myClaimForUri: selectMyClaimForUri(state),
// 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: selectIsStillEditing(state),
isResolvingUri: selectIsResolvingPublishUris(state),
totalRewardValue: selectUnclaimedRewardValue(state),
});
const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
clearPublish: () => dispatch(doClearPublish()),
resolveUri: uri => dispatch(doResolveUri(uri)),
publish: params => dispatch(doPublish(params)),
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
});
export default connect(
null,
select,
perform
)(SelectThumbnail);
)(PublishPage);

View file

@ -122,7 +122,8 @@ class SelectThumbnail extends React.PureComponent<Props, State> {
{status === THUMBNAIL_STATUSES.READY && (
<FileSelector
currentPath={thumbnailPath}
fileLabel={__('Choose Thumbnail')}
label={__('Thumbnail')}
placeholder={__('Choose a thumbnail')}
filters={filters}
onFileChosen={path => openModal(MODALS.CONFIRM_THUMBNAIL_UPLOAD, { path })}
/>
@ -160,6 +161,18 @@ class SelectThumbnail extends React.PureComponent<Props, State> {
)}
{status === THUMBNAIL_STATUSES.IN_PROGRESS && <p>{__('Uploading thumbnail')}...</p>}
<p className="help">
{(status === undefined && __('You should reselect your file to choose a thumbnail')) ||
(status === THUMBNAIL_STATUSES.API_DOWN ? (
__('Enter a URL for your thumbnail.')
) : (
<React.Fragment>
{__('Upload your thumbnail (.png/.jpg/.jpeg/.gif) to')}{' '}
<Button button="link" label={__('spee.ch')} href="https://spee.ch/about" />.{' '}
{__('Recommended size: 800x450 (16:9)')}
</React.Fragment>
))}
</p>
</div>
);
}

View file

@ -34,23 +34,23 @@ function SideBar(props: Props) {
...buildLink(null, __('Home'), ICONS.HOME),
},
{
...buildLink(PAGES.SUBSCRIPTIONS, __('Subscriptions'), ICONS.SUBSCRIPTION),
},
{
...buildLink(PAGES.PUBLISHED, __('Publishes'), ICONS.PUBLISHED),
...buildLink(PAGES.FOLLOWING, __('Following'), ICONS.SUBSCRIPTION),
},
{
...buildLink(PAGES.LIBRARY, __('Library'), ICONS.LIBRARY),
},
{
...buildLink(PAGES.PUBLISHED, __('Publishes'), ICONS.PUBLISHED),
},
].map(renderLink)}
<li>
<Button
navigate="/$/tags/edit"
navigate="/$/following/edit"
icon={ICONS.EDIT}
className="navigation__link"
activeClass="navigation__link--active"
label={__('Following')}
label={__('Edit')}
/>
</li>
</ul>

View file

@ -15,33 +15,48 @@ type Props = {
followedTags: Array<Tag>,
doToggleTagFollow: string => void,
doAddTag: string => void,
onSelect?: Tag => void,
};
export default function TagSelect(props: Props) {
const { unfollowedTags, followedTags, doToggleTagFollow, doAddTag } = props;
const { unfollowedTags, followedTags, doToggleTagFollow, doAddTag, onSelect } = props;
const [newTag, setNewTag] = useState('');
let tags = unfollowedTags.slice();
if (newTag) {
tags = [{ name: newTag }, ...tags];
tags.unshift({ name: newTag });
}
const suggestedTags = tags
.filter(({ name }) => (newTag ? name.toLowerCase().includes(newTag.toLowerCase()) : true))
.slice(0, 5);
const doesTagMatch = ({ name }) => (newTag ? name.toLowerCase().includes(newTag.toLowerCase()) : true);
const suggestedTags = tags.filter(doesTagMatch).slice(0, 5);
const suggestedTransitions = useTransition(suggestedTags, tag => tag.name, unfollowedTagsAnimation);
function onChange(e) {
setNewTag(e.target.value);
}
function handleSubmit() {
function handleSubmit(e) {
e.preventDefault();
setNewTag('');
if (!unfollowedTags.includes(newTag)) {
doAddTag(newTag);
}
if (onSelect) {
onSelect({ name: newTag });
} else {
if (!unfollowedTags.includes(newTag)) {
doAddTag(newTag);
}
if (!followedTags.includes(newTag)) {
doToggleTagFollow(newTag);
if (!followedTags.includes(newTag)) {
doToggleTagFollow(newTag);
}
}
}
function handleTagClick(tag) {
if (onSelect) {
onSelect(tag);
} else {
doToggleTagFollow(tag);
}
}
@ -59,7 +74,7 @@ export default function TagSelect(props: Props) {
<ul className="tags">
{suggestedTransitions.map(({ item, key, props }) => (
<animated.li key={key} style={props}>
<Tag name={item.name} type="add" onClick={() => doToggleTagFollow(item.name)} />
<Tag name={item.name} type="add" onClick={() => handleTagClick(item)} />
</animated.li>
))}
{!suggestedTransitions.length && <p className="empty tags__empty-message">No suggested tags</p>}

View file

@ -8,10 +8,18 @@ import usePersistedState from 'util/use-persisted-state';
import { useTransition, animated } from 'react-spring';
type Props = {
followedTags: Array<Tag>,
showClose: boolean,
title: string,
doDeleteTag: string => void,
followedTags: Array<Tag>,
doToggleTagFollow: string => void,
// Ovverides
// The default component is for following tags
title?: string,
help?: string,
empty?: string,
tagsChosen?: Array<Tag>,
onSelect?: Tag => void,
onRemove?: Tag => void,
};
const tagsAnimation = {
@ -21,23 +29,32 @@ const tagsAnimation = {
};
export default function TagSelect(props: Props) {
const { title, followedTags, showClose, doDeleteTag } = props;
const { showClose, followedTags, doToggleTagFollow, title, help, empty, tagsChosen, onSelect, onRemove } = props;
const [hasClosed, setHasClosed] = usePersistedState('tag-select:has-closed', false);
const tagsToDisplay = tagsChosen || followedTags;
const transitions = useTransition(tagsToDisplay, tag => tag.name, tagsAnimation);
function handleClose() {
setHasClosed(true);
}
const transitions = useTransition(followedTags.map(tag => tag), tag => tag.name, tagsAnimation);
function handleTagClick(tag) {
if (onRemove) {
onRemove(tag);
} else {
doToggleTagFollow(tag.name);
}
}
return (
((showClose && !hasClosed) || !showClose) && (
<div className="card--section">
<h2 className="card__title card__title--flex-between">
{title}
{showClose && !hasClosed && <Button button="close" icon={ICONS.REMOVE} onClick={handleClose} />}
</h2>
<p className="help">{__("The tags you follow will change what's trending for you.")}</p>
{title !== false && (
<h2 className="card__title card__title--flex-between">
{title}
{showClose && !hasClosed && <Button button="close" icon={ICONS.REMOVE} onClick={handleClose} />}
</h2>
)}
<div className="card__content">
<ul className="tags--remove">
@ -47,16 +64,19 @@ export default function TagSelect(props: Props) {
name={item.name}
type="remove"
onClick={() => {
doDeleteTag(item.name);
handleTagClick(item);
}}
/>
</animated.li>
))}
{!transitions.length && (
<div className="card__subtitle">{__("You aren't following any tags, try searching for one.")}</div>
<div className="empty">{empty || __("You aren't following any tags, try searching for one.")}</div>
)}
</ul>
<TagsSearch />
<TagsSearch onSelect={onSelect} />
{help !== false && (
<p className="help">{help || __("The tags you follow will change what's trending for you.")}</p>
)}
</div>
</div>
)

View file

@ -2,6 +2,8 @@
import React from 'react';
import Button from 'component/button';
import { buildURI } from 'lbry-redux';
import Tooltip from 'component/common/tooltip';
import ClaimPreview from 'component/claimPreview';
type Props = {
isResolvingUri: boolean,
@ -61,7 +63,7 @@ class UriIndicator extends React.PureComponent<Props> {
return (
<Button className="button--uri-indicator" navigate={channelLink}>
{inner}
<Tooltip label={<ClaimPreview uri={channelLink} type="small" />}>{inner}</Tooltip>
</Button>
);
} else {

View file

@ -20,3 +20,4 @@ export const SEARCH = 'search';
export const TRANSACTIONS = 'transactions';
export const TAGS = 'tags';
export const WALLET = 'wallet';
export const FOLLOWING = 'following';

View file

@ -232,9 +232,9 @@ class FilePage extends React.Component<Props> {
</div>
{claimIsMine && (
<div className="media__subtext--large">
<p>
{viewCount} {viewCount !== 1 ? __('Views') : __('View')}
</div>
</p>
)}
</div>

View file

@ -1,9 +1,11 @@
import { connect } from 'react-redux';
import { selectFollowedTags } from 'lbry-redux';
import { selectSubscriptions } from 'redux/selectors/subscriptions';
import TagsEdit from './view';
const select = state => ({
followedTags: selectFollowedTags(state),
subscribedChannels: selectSubscriptions(state),
});
const perform = {};

View file

@ -0,0 +1,30 @@
// @flow
import React from 'react';
import Page from 'component/page';
import TagsSelect from 'component/tagsSelect';
import ClaimList from 'component/claimList';
type Props = {
subscribedChannels: Array<{ uri: string }>,
};
function DiscoverPage(props: Props) {
const { subscribedChannels } = props;
return (
<Page>
<div className="card">
<TagsSelect showClose={false} title={__('Find New Tags To Follow')} />
</div>
<div className="card">
<ClaimList
header={<h1>{__('Channels You Are Following')}</h1>}
empty={__("You aren't following any channels.")}
uris={subscribedChannels.map(({ uri }) => uri)}
/>
</div>
</Page>
);
}
export default DiscoverPage;

View file

@ -1,46 +1,14 @@
import { connect } from 'react-redux';
import { doResolveUri, selectBalance } from 'lbry-redux';
import {
selectPublishFormValues,
selectIsStillEditing,
selectMyClaimForUri,
selectIsResolvingPublishUris,
selectTakeOverAmount,
} from 'redux/selectors/publish';
import {
doResetThumbnailStatus,
doClearPublish,
doUpdatePublishForm,
doPublish,
doPrepareEdit,
} from 'redux/actions/publish';
import { selectBalance } from 'lbry-redux';
import { selectUnclaimedRewardValue } from 'lbryinc';
import PublishPage from './view';
const select = state => ({
...selectPublishFormValues(state),
// The winning claim for a short lbry uri
amountNeededForTakeover: selectTakeOverAmount(state),
// My previously published claims under this short lbry uri
myClaimForUri: selectMyClaimForUri(state),
// 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: selectIsStillEditing(state),
balance: selectBalance(state),
isResolvingUri: selectIsResolvingPublishUris(state),
totalRewardValue: selectUnclaimedRewardValue(state),
});
const perform = dispatch => ({
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
clearPublish: () => dispatch(doClearPublish()),
resolveUri: uri => dispatch(doResolveUri(uri)),
publish: params => dispatch(doPublish(params)),
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
});
export default connect(
select,
perform
null
)(PublishPage);

View file

@ -1,3 +1,4 @@
// @flow
import React, { Fragment } from 'react';
import PublishForm from 'component/publishForm';
import Page from 'component/page';
@ -6,64 +7,67 @@ import LbcSymbol from 'component/common/lbc-symbol';
import CreditAmount from 'component/common/credit-amount';
import Button from 'component/button';
class PublishPage extends React.PureComponent {
scrollToTop = () => {
type Props = {
balance: number,
totalRewardValue: number,
};
function PublishPage(props: Props) {
const { balance, totalRewardValue } = props;
const totalRewardRounded = Math.floor(totalRewardValue / 10) * 10;
function scrollToTop() {
const mainContent = document.querySelector('main');
if (mainContent) {
mainContent.scrollTop = 0; // It would be nice to animate this
}
};
render() {
const { balance, totalRewardValue } = this.props;
const totalRewardRounded = Math.floor(totalRewardValue / 10) * 10;
return (
<Page>
{balance === 0 && (
<Fragment>
<Yrbl
title={__("You can't publish things quite yet")}
subtitle={
<Fragment>
<p>
{__(
'LBRY uses a blockchain, which is a fancy way of saying that users (you) are in control of your data.'
)}
</p>
<p>
{__('Because of the blockchain, some actions require LBRY credits')} (
<LbcSymbol />
).
</p>
<p>
<LbcSymbol />{' '}
{__(
'allows you to do some neat things, like paying your favorite creators for their content. And no company can stop you.'
)}
</p>
</Fragment>
}
/>
<section className="card card--section">
<header className="card__header">
<h1 className="card__title">{__('LBRY Credits Required')}</h1>
</header>
<p className="card__subtitle">
{__(' There are a variety of ways to get credits, including more than')}{' '}
<CreditAmount inheritStyle amount={totalRewardRounded} />{' '}
{__('in free rewards for participating in the LBRY beta.')}
</p>
<div className="card__actions">
<Button button="link" navigate="/$/rewards" label={__('Checkout the rewards')} />
</div>
</section>
</Fragment>
)}
<PublishForm {...this.props} scrollToTop={this.scrollToTop} />
</Page>
);
}
return (
<Page>
{balance === 0 && (
<Fragment>
<Yrbl
title={__("You can't publish things quite yet")}
subtitle={
<Fragment>
<p>
{__(
'LBRY uses a blockchain, which is a fancy way of saying that users (you) are in control of your data.'
)}
</p>
<p>
{__('Because of the blockchain, some actions require LBRY credits')} (
<LbcSymbol />
).
</p>
<p>
<LbcSymbol />{' '}
{__(
'allows you to do some neat things, like paying your favorite creators for their content. And no company can stop you.'
)}
</p>
</Fragment>
}
/>
<section className="card card--section">
<header className="card__header">
<h1 className="card__title">{__('LBRY Credits Required')}</h1>
</header>
<p className="card__subtitle">
{__(' There are a variety of ways to get credits, including more than')}{' '}
<CreditAmount inheritStyle amount={totalRewardRounded} />{' '}
{__('in free rewards for participating in the LBRY beta.')}
</p>
<div className="card__actions">
<Button button="link" navigate="/$/rewards" label={__('Checkout the rewards')} />
</div>
</section>
</Fragment>
)}
<PublishForm scrollToTop={scrollToTop} />
</Page>
);
}
export default PublishPage;

View file

@ -2,7 +2,7 @@
import * as ICONS from 'constants/icons';
import React, { useEffect, Fragment } from 'react';
import { isURIValid, normalizeURI } from 'lbry-redux';
import ClaimListItem from 'component/claimListItem';
import ClaimPreview from 'component/claimPreview';
import ClaimList from 'component/claimList';
import Page from 'component/page';
import SearchOptions from 'component/searchOptions';
@ -29,7 +29,6 @@ export default function SearchPage(props: Props) {
useEffect(() => {
if (urlQuery) {
console.log('search', urlQuery);
search(urlQuery);
}
}, [search, urlQuery]);
@ -44,7 +43,7 @@ export default function SearchPage(props: Props) {
<Button button="alt" navigate={uri} className="media__uri">
{uri}
</Button>
<ClaimListItem uri={uri} type="large" />
<ClaimPreview uri={uri} type="large" />
</header>
)}

View file

@ -36,7 +36,7 @@ export default function SubscriptionsPage(props: Props) {
const viewingSuggestedSubs = urlParams.get('view');
function onClick() {
let url = `/$/${PAGES.SUBSCRIPTIONS}`;
let url = `/$/${PAGES.FOLLOWING}`;
if (!viewingSuggestedSubs) {
url += '?view=discover';
}
@ -54,6 +54,7 @@ export default function SubscriptionsPage(props: Props) {
const ids = idString.split(',');
const options = {
channel_ids: ids,
order_by: ['release_time'],
};
doClaimSearch(20, options);
@ -72,7 +73,8 @@ export default function SubscriptionsPage(props: Props) {
onClick={() => onClick()}
/>
}
uris={viewingSuggestedSubs ? suggestedSubscriptions.map(sub => sub.uri) : uris}
// Fix the need to reverse this
uris={viewingSuggestedSubs ? suggestedSubscriptions.map(sub => sub.uri) : uris.reverse()}
/>
</div>
</Page>

View file

@ -1,18 +0,0 @@
// @flow
import React from 'react';
import Page from 'component/page';
import TagsSelect from 'component/tagsSelect';
type Props = {};
function DiscoverPage(props: Props) {
return (
<Page>
<div className="card">
<TagsSelect showClose={false} title={__('Find New Tags To Follow')} />
</div>
</Page>
);
}
export default DiscoverPage;

View file

@ -15,6 +15,7 @@ import {
} from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app';
import { selectosNotificationsEnabled } from 'redux/selectors/settings';
import { selectMyClaimForUri, selectPublishFormValues } from 'redux/selectors/publish';
import { push } from 'connected-react-router';
import analytics from 'analytics';
import { formatLbryUriForWeb } from 'util/uri';
@ -146,7 +147,7 @@ export const doPrepareEdit = (claim: StreamClaim, uri: string, fileInfo: FileLis
// use same values as default state
// fee will be undefined for free content
fee = {
amount: 0,
amount: '0',
currency: 'LBC',
},
languages,
@ -159,11 +160,11 @@ export const doPrepareEdit = (claim: StreamClaim, uri: string, fileInfo: FileLis
const publishData: UpdatePublishFormData = {
name,
channel: channelName,
bid: amount,
bid: Number(amount),
contentIsFree: !fee.amount,
author,
description,
fee: { amount: fee.amount, currency: fee.currency },
fee,
languages,
thumbnail: thumbnail ? thumbnail.url : null,
title,
@ -201,10 +202,13 @@ export const doPrepareEdit = (claim: StreamClaim, uri: string, fileInfo: FileLis
dispatch({ type: ACTIONS.DO_PREPARE_EDIT, data: publishData });
};
export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getState: () => {}) => {
export const doPublish = () => (dispatch: Dispatch, getState: () => {}) => {
dispatch({ type: ACTIONS.PUBLISH_START });
const state = getState();
const publishData = selectPublishFormValues(state);
const myClaimForUri = selectMyClaimForUri(state);
const myChannels = selectMyChannelClaims(state);
const myClaims = selectMyClaimsWithoutChannels(state);
@ -214,8 +218,9 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat
filePath,
description,
language,
license,
licenseUrl,
licenseType,
otherLicenseDescription,
thumbnail,
channel,
title,
@ -223,8 +228,19 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat
fee,
uri,
nsfw,
claim,
} = params;
tags,
locations,
} = publishData;
let publishingLicense;
switch (licenseType) {
case COPYRIGHT:
case OTHER:
publishingLicense = otherLicenseDescription;
break;
default:
publishingLicense = licenseType;
}
// get the claim id from the channel name, we will use that instead
const namedChannelClaim = myChannels.find(myChannel => myChannel.name === channel);
@ -244,29 +260,19 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat
fee_amount?: string,
} = {
name,
bid: creditsToString(bid),
title,
license,
languages: [language],
description,
tags: (claim && claim.value.tags) || [],
locations: claim && claim.value.locations,
locations,
bid: creditsToString(bid),
license: publishingLicense,
languages: [language],
tags: tags && tags.map(tag => tag.name),
license_url: licenseType === COPYRIGHT ? '' : licenseUrl,
thumbnail_url: thumbnail,
};
// Temporary solution to keep the same publish flow with the new tags api
// Eventually we will allow users to enter their own tags on publish
// `nsfw` will probably be removed
if (licenseUrl) {
publishPayload.license_url = licenseUrl;
}
if (thumbnail) {
publishPayload.thumbnail_url = thumbnail;
}
if (claim && claim.value.release_time) {
publishPayload.release_time = Number(claim.value.release_time);
if (myClaimForUri && myClaimForUri.value.release_time) {
publishPayload.release_time = Number(myClaimForUri.value.release_time);
}
if (nsfw) {
@ -346,23 +352,25 @@ export const doCheckPendingPublishes = () => (dispatch: Dispatch, getState: GetS
const checkFileList = () => {
Lbry.claim_list().then(claims => {
claims.forEach(claim => {
// If it's confirmed, check if it was pending previously
if (claim.confirmations > 0 && pendingById[claim.claim_id]) {
delete pendingById[claim.claim_id];
if (claims) {
claims.forEach(claim => {
// If it's confirmed, check if it was pending previously
if (claim.confirmations > 0 && pendingById[claim.claim_id]) {
delete pendingById[claim.claim_id];
// If it's confirmed, check if we should notify the user
if (selectosNotificationsEnabled(getState())) {
const notif = new window.Notification('LBRY Publish Complete', {
body: `${claim.value.title} has been published to lbry://${claim.name}. Click here to view it`,
silent: false,
});
notif.onclick = () => {
dispatch(push(formatLbryUriForWeb(claim.permanent_url)));
};
// If it's confirmed, check if we should notify the user
if (selectosNotificationsEnabled(getState())) {
const notif = new window.Notification('LBRY Publish Complete', {
body: `${claim.value.title} has been published to lbry://${claim.name}. Click here to view it`,
silent: false,
});
notif.onclick = () => {
dispatch(push(formatLbryUriForWeb(claim.permanent_url)));
};
}
}
}
});
});
}
dispatch({
type: ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED,

View file

@ -27,6 +27,7 @@ type PublishState = {
bidError: ?string,
otherLicenseDescription: string,
licenseUrl: string,
tags: Array<string>,
};
const defaultState: PublishState = {
@ -53,6 +54,7 @@ const defaultState: PublishState = {
licenseType: 'None',
otherLicenseDescription: 'All rights reserved',
licenseUrl: '',
tags: [],
publishing: false,
publishSuccess: false,
publishError: undefined,

View file

@ -18,6 +18,12 @@ export const selectPublishFormValues = createSelector(
}
);
export const makeSelectPublishFormValue = item =>
createSelector(
selectState,
state => state[item]
);
// Is the current uri the same as the uri they clicked "edit" on
export const selectIsStillEditing = createSelector(
selectPublishFormValues,

View file

@ -1,4 +1,4 @@
.file-list__header {
.claim-list__header {
display: flex;
align-items: center;
min-height: 4.5rem;
@ -31,12 +31,13 @@
}
}
.file-list__header--small {
.claim-list__header--small {
height: 3rem;
min-height: 3rem;
font-size: 1em;
}
.file-list__dropdown {
.claim-list__dropdown {
background-position: 95% center;
background-repeat: no-repeat;
background-size: 1.2rem;
@ -50,8 +51,8 @@
background-color: lighten($lbry-black, 10%);
}
.file-list__header,
.file-list__dropdown {
.claim-list__header,
.claim-list__dropdown {
background-color: lighten($lbry-black, 10%);
[data-mode='dark'] & {
@ -59,17 +60,17 @@
}
}
.file-list__header-text {
.claim-list__header-text {
display: flex;
align-items: center;
}
.file-list__header-text,
.file-list__dropdown {
.claim-list__header-text,
.claim-list__dropdown {
font-size: 1.3rem;
}
.file-list__alt-controls {
.claim-list__alt-controls {
display: flex;
align-items: center;
margin-left: auto;
@ -80,7 +81,7 @@
}
}
.file-list__item {
.claim-list__item {
display: flex;
position: relative;
font-size: 1.3rem;
@ -103,12 +104,12 @@
}
}
.file-list__item--injected,
.file-list__item {
border-bottom: 1px solid rgba($lbry-teal-5, 0.1);
.claim-list__item--injected,
.claim-list__item + .claim-list__item {
border-top: 1px solid rgba($lbry-teal-5, 0.1);
}
.file-list__item--large {
.claim-list__item--large {
@include mediaThumbHoverZoom;
font-size: 1.6rem;
border-bottom: 0;
@ -124,36 +125,49 @@
}
}
.file-list__item-metadata {
.claim-list__pending {
cursor: pointer;
opacity: 0.6;
&:hover {
background-color: $lbry-white;
[data-mode='dark'] & {
background-color: lighten($lbry-black, 5%);
}
}
}
.claim-list__item-metadata {
display: flex;
flex-direction: column;
width: 100%;
}
.file-list__item-info {
.claim-list__item-info {
align-items: flex-start;
}
.file-list__item-info,
.file-list__item-properties {
.claim-list__item-info,
.claim-list__item-properties {
display: flex;
justify-content: space-between;
}
.file-list__item-properties {
.claim-list__item-properties {
align-items: flex-end;
}
.file-list__item-title {
.claim-list__item-title {
font-weight: 600;
margin-right: auto;
}
.file-list__item-tags {
.claim-list__item-tags {
margin-left: 0;
}
.file-list__meta {
.claim-list__meta {
padding: var(--spacing-medium);
background-color: lighten($lbry-teal-5, 55%);
}

View file

@ -1,16 +1,36 @@
@import '~@lbry/components/sass/form/_index.scss';
// replace this
form {
// setting the font size here sizes everything within
&:not(:last-child) {
margin-bottom: var(--spacing-s);
}
}
input,
select {
height: var(--spacing-l);
border: 1px solid;
}
checkbox-element,
radio-element,
select {
cursor: pointer;
}
textarea {
&::placeholder {
opacity: 0.4;
}
}
// lbry/components overrides and minor styles
// Some items have very specific styling
// This is because many styles inside `lbry/components/sass/form/` are very specific
// As styles become hardened here, they _should_ slowly move over to that repo
input,
textarea,
select {
border-radius: var(--input-border-radius);
}
input-submit {
align-items: center;
}
@ -21,7 +41,8 @@ input[type='number'] {
input[type='text'],
input[type='number'],
select {
select,
textarea {
padding-bottom: 0.1em;
[data-mode='dark'] & {
@ -31,6 +52,14 @@ select {
}
}
input,
select,
textarea {
border-color: lighten($lbry-black, 20%);
border-radius: var(--input-border-radius);
border-width: 1px;
}
fieldset-section {
label {
width: auto;

View file

@ -5,6 +5,7 @@
padding-top: var(--header-height);
padding-left: var(--spacing-large);
padding-right: var(--spacing-large);
padding-bottom: var(--spacing-large);
background-color: mix($lbry-white, $lbry-gray-1, 70%);
display: flex;

View file

@ -9,7 +9,7 @@
.placeholder {
display: flex;
&.file-list__item-title {
&.claim-list__item-title {
width: 100%;
height: 3rem;
}