updated publish ux/ui

This commit is contained in:
bill bittner 2018-03-05 22:45:39 -08:00
parent b7b3a78730
commit 4da04d833c
8 changed files with 137 additions and 109 deletions

View file

@ -1,7 +1,7 @@
import { connect } from 'react-redux';
import { updateLoggedInChannel } from 'actions/channel';
import View from './view';
import {updateSelectedChannel} from '../../actions/publish';
import {updateSelectedChannel} from 'actions/publish';
const mapDispatchToProps = dispatch => {
return {

View file

@ -119,38 +119,41 @@ class ChannelCreateForm extends React.Component {
return (
<div>
{ !this.state.status ? (
<form id="publish-channel-form">
<p id="input-error-channel-name" className="info-message-placeholder info-message--failure">{this.state.error}</p>
<div className="row row--wide row--short">
<div className="column column--3 column--sml-10">
<label className="label" htmlFor="new-channel-name">Name:</label>
</div><div className="column column--6 column--sml-10">
<div className="input-text--primary flex-container--row flex-container--left-bottom span--relative">
<form id='publish-channel-form'>
<div className='row row--wide row--short'>
<div className='column column--3 column--sml-10'>
<label className='label' htmlFor='new-channel-name'>Name:</label>
</div><div className='column column--6 column--sml-10'>
<div className='input-text--primary flex-container--row flex-container--left-bottom span--relative'>
<span>@</span>
<input type="text" name="channel" id="new-channel-name" className="input-text" placeholder="exampleChannelName" value={this.state.channel} onChange={this.handleChannelInput} />
{ (this.state.channel && !this.state.error) && <span id="input-success-channel-name" className="info-message--success span--absolute">{'\u2713'}</span> }
{ this.state.error && <span id="input-success-channel-name" className="info-message--failure span--absolute">{'\u2716'}</span> }
<input type='text' name='channel' id='new-channel-name' className='input-text' placeholder='exampleChannelName' value={this.state.channel} onChange={this.handleChannelInput} />
{ (this.state.channel && !this.state.error) && <span id='input-success-channel-name' className='info-message--success span--absolute'>{'\u2713'}</span> }
{ this.state.error && <span id='input-success-channel-name' className='info-message--failure span--absolute'>{'\u2716'}</span> }
</div>
</div>
</div>
<div className="row row--wide row--short">
<div className="column column--3 column--sml-10">
<label className="label" htmlFor="new-channel-password">Password:</label>
</div><div className="column column--6 column--sml-10">
<div className="input-text--primary">
<input type="password" name="password" id="new-channel-password" className="input-text" placeholder="" value={this.state.password} onChange={this.handleInput} />
<div className='row row--wide row--short'>
<div className='column column--3 column--sml-10'>
<label className='label' htmlFor='new-channel-password'>Password:</label>
</div><div className='column column--6 column--sml-10'>
<div className='input-text--primary'>
<input type='password' name='password' id='new-channel-password' className='input-text' placeholder='' value={this.state.password} onChange={this.handleInput} />
</div>
</div>
</div>
<div className="row row--wide">
<button className="button--primary" onClick={this.createChannel}>Create Channel</button>
{this.state.error ? (
<p className='info-message--failure'>{this.state.error}</p>
) : (
<p className='info-message'>Choose a name and password for your channel</p>
)}
<div className='row row--wide'>
<button className='button--primary' onClick={this.createChannel}>Create Channel</button>
</div>
</form>
) : (
<div>
<p className="fine-print">{this.state.status}</p>
<ProgressBar size={12}/>
<p className='fine-print'>{this.state.status}</p>
<ProgressBar size={12} />
</div>
)}
</div>

View file

@ -26,7 +26,7 @@ class ChannelLoginForm extends React.Component {
'Content-Type': 'application/json',
}),
credentials: 'include',
}
};
request('login', params)
.then(({success, channelName, shortChannelId, channelClaimId, message}) => {
console.log('loginToChannel success:', success);
@ -47,30 +47,33 @@ class ChannelLoginForm extends React.Component {
}
render () {
return (
<form id="channel-login-form">
<p id="login-error-display-element" className="info-message-placeholder info-message--failure">{this.state.error}</p>
<div className="row row--wide row--short">
<div className="column column--3 column--sml-10">
<label className="label" htmlFor="channel-login-name-input">Name:</label>
</div><div className="column column--6 column--sml-10">
<div className="input-text--primary flex-container--row flex-container--left-bottom">
<form id='channel-login-form'>
<div className='row row--wide row--short'>
<div className='column column--3 column--sml-10'>
<label className='label' htmlFor='channel-login-name-input'>Name:</label>
</div><div className='column column--6 column--sml-10'>
<div className='input-text--primary flex-container--row flex-container--left-bottom'>
<span>@</span>
<input type="text" id="channel-login-name-input" className="input-text" name="name" placeholder="Your Channel Name" value={this.state.channelName} onChange={this.handleInput}/>
<input type='text' id='channel-login-name-input' className='input-text' name='name' placeholder='Your Channel Name' value={this.state.channelName} onChange={this.handleInput} />
</div>
</div>
</div>
<div className="row row--wide row--short">
<div className="column column--3 column--sml-10">
<label className="label" htmlFor="channel-login-password-input" >Password:</label>
</div><div className="column column--6 column--sml-10">
<div className="input-text--primary">
<input type="password" id="channel-login-password-input" name="password" className="input-text" placeholder="" value={this.state.channelPassword} onChange={this.handleInput}/>
<div className='row row--wide row--short'>
<div className='column column--3 column--sml-10'>
<label className='label' htmlFor='channel-login-password-input' >Password:</label>
</div><div className='column column--6 column--sml-10'>
<div className='input-text--primary'>
<input type='password' id='channel-login-password-input' name='password' className='input-text' placeholder='' value={this.state.channelPassword} onChange={this.handleInput} />
</div>
</div>
</div>
<div className="row row--wide">
<button className="button--primary" onClick={this.loginToChannel}>Authenticate</button>
{ this.state.error ? (
<p className='info-message--failure'>{this.state.error}</p>
) : (
<p className='info-message'>Enter the name and password for your channel</p>
)}
<div className='row row--wide'>
<button className='button--primary' onClick={this.loginToChannel}>Authenticate</button>
</div>
</form>
);

View file

@ -24,24 +24,28 @@ class ChannelSelect extends React.Component {
render () {
return (
<div>
<p id="input-error-channel-select" className="info-message-placeholder info-message--failure">{this.props.channelError}</p>
<form>
<div className="column column--3 column--med-10">
<input type="radio" name="anonymous-or-channel" id="anonymous-radio" className="input-radio" value="anonymous" checked={!this.props.publishInChannel} onChange={this.toggleAnonymousPublish}/>
<label className="label label--pointer" htmlFor="anonymous-radio">Anonymous</label>
<div className='column column--3 column--med-10'>
<input type='radio' name='anonymous-or-channel' id='anonymous-radio' className='input-radio' value='anonymous' checked={!this.props.publishInChannel} onChange={this.toggleAnonymousPublish} />
<label className='label label--pointer' htmlFor='anonymous-radio'>Anonymous</label>
</div>
<div className="column column--7 column--med-10">
<input type="radio" name="anonymous-or-channel" id="channel-radio" className="input-radio" value="in a channel" checked={this.props.publishInChannel} onChange={this.toggleAnonymousPublish}/>
<label className="label label--pointer" htmlFor="channel-radio">In a channel</label>
<div className='column column--7 column--med-10'>
<input type='radio' name='anonymous-or-channel' id='channel-radio' className='input-radio' value='in a channel' checked={this.props.publishInChannel} onChange={this.toggleAnonymousPublish} />
<label className='label label--pointer' htmlFor='channel-radio'>In a channel</label>
</div>
{ this.props.channelError ? (
<p className='info-message--failure'>{this.props.channelError}</p>
) : (
<p className='info-message'>Publish anonymously or in a channel</p>
)}
</form>
{ this.props.publishInChannel && (
<div>
<div className="column column--3">
<label className="label" htmlFor="channel-name-select">Channel:</label>
</div><div className="column column--7">
<select type="text" id="channel-name-select" className="select select--arrow" value={this.props.selectedChannel} onChange={this.handleSelection}>
{ this.props.loggedInChannelName && <option value={this.props.loggedInChannelName} id="publish-channel-select-channel-option">{this.props.loggedInChannelName}</option> }
<div className='column column--3'>
<label className='label' htmlFor='channel-name-select'>Channel:</label>
</div><div className='column column--7'>
<select type='text' id='channel-name-select' className='select select--arrow' value={this.props.selectedChannel} onChange={this.handleSelection}>
{ this.props.loggedInChannelName && <option value={this.props.loggedInChannelName} id='publish-channel-select-channel-option'>{this.props.loggedInChannelName}</option> }
<option value={states.LOGIN}>Existing</option>
<option value={states.CREATE}>New</option>
</select>

View file

@ -51,10 +51,14 @@ class PublishThumbnailInput extends React.Component {
}
handleVideoLoadedData (event) {
const duration = event.target.duration;
const totalMinutes = Math.floor(duration / 60);
const totalSeconds = Math.floor(duration % 60);
// set the slider
this.setState({
sliderMaxRange: duration * 100,
sliderValue : duration * 100 / 2,
totalMinutes,
totalSeconds,
});
// update the current time of the video
let video = document.getElementById('video-thumb-player');
@ -88,15 +92,10 @@ class PublishThumbnailInput extends React.Component {
}
}
render () {
const { error, videoSource, sliderMinRange, sliderMaxRange, sliderValue } = this.state;
const { error, videoSource, sliderMinRange, sliderMaxRange, sliderValue, totalMinutes, totalSeconds } = this.state;
return (
<div>
<div>
{ error ? (
<p className='info-message--failure'>{error}</p>
) : (
<p className='info-message'>Use slider to set thumbnail:</p>
)}
<label className='label'>Thumbnail:</label>
<video
id='video-thumb-player'
preload='metadata'
@ -109,7 +108,12 @@ class PublishThumbnailInput extends React.Component {
/>
{
sliderValue ? (
<div className='slide-container'>
<div>
<div className='flex-container--row flex-container--space-between-center' style={{width: '100%'}}>
<span className='info-message'>0'00"</span>
<span className='info-message'>{totalMinutes}'{totalSeconds}"</span>
</div>
<div>
<input
type='range'
min={sliderMinRange}
@ -119,11 +123,16 @@ class PublishThumbnailInput extends React.Component {
onChange={this.handleSliderChange}
/>
</div>
</div>
) : (
<p className='info-message' >loading... </p>
)
}
</div>
{ error ? (
<p className='info-message--failure'>{error}</p>
) : (
<p className='info-message'>Use slider to set thumbnail</p>
)}
</div>
);
}

View file

@ -14,10 +14,14 @@ class PublishUrlInput extends React.Component {
}
}
componentWillReceiveProps ({ claim, fileName }) {
if (!claim) {
// if a new file was chosen, update the claim name
if (fileName !== this.props.fileName) {
return this.setClaimName(fileName);
}
this.checkClaimIsAvailable(claim);
// if the claim has updated, check its availability
if (claim !== this.props.claim) {
this.validateClaim(claim);
}
}
handleInput (event) {
let value = event.target.value;
@ -35,35 +39,42 @@ class PublishUrlInput extends React.Component {
const cleanClaimName = this.cleanseInput(fileNameWithoutEnding);
this.props.onClaimChange(cleanClaimName);
}
checkClaimIsAvailable (claim) {
validateClaim (claim) {
if (!claim) {
return this.props.onUrlError('Enter a url above');
}
request(`/api/claim/availability/${claim}`)
.then(() => {
.then(response => {
console.log('api/claim/availability response:', response);
this.props.onUrlError(null);
})
.catch((error) => {
console.log('api/claim/availability error:', error);
this.props.onUrlError(error.message);
});
}
render () {
const { claim, loggedInChannelName, loggedInChannelShortId, publishInChannel, selectedChannel, urlError } = this.props;
return (
<div>
<p id='input-error-claim-name' className='info-message-placeholder info-message--failure'>{this.props.urlError}</p>
<div className='column column--3 column--sml-10'>
<label className='label'>URL:</label>
</div><div className='column column--7 column--sml-10 input-text--primary span--relative'>
<div className='column column--10 column--sml-10'>
<div className='input-text--primary span--relative'>
<span className='url-text--secondary'>spee.ch / </span>
<UrlMiddle
publishInChannel={this.props.publishInChannel}
selectedChannel={this.props.selectedChannel}
loggedInChannelName={this.props.loggedInChannelName}
loggedInChannelShortId={this.props.loggedInChannelShortId}
publishInChannel={publishInChannel}
selectedChannel={selectedChannel}
loggedInChannelName={loggedInChannelName}
loggedInChannelShortId={loggedInChannelShortId}
/>
<input type='text' id='claim-name-input' className='input-text' name='claim' placeholder='your-url-here' onChange={this.handleInput} value={this.props.claim} />
{ (this.props.claim && !this.props.urlError) && <span id='input-success-claim-name' className='info-message--success span--absolute'>{'\u2713'}</span> }
{ this.props.urlError && <span id='input-success-channel-name' className='info-message--failure span--absolute'>{'\u2716'}</span> }
<input type='text' id='claim-name-input' className='input-text' name='claim' placeholder='your-url-here' onChange={this.handleInput} value={claim} />
{ (claim && !urlError) && <span id='input-success-claim-name' className='info-message--success span--absolute'>{'\u2713'}</span> }
{ urlError && <span id='input-success-channel-name' className='info-message--failure span--absolute'>{'\u2716'}</span> }
</div>
<div>
{ urlError ? (
<p id='input-error-claim-name' className='info-message--failure'>{urlError}</p>
) : (
<p className='info-message'>Choose a custom url</p>
)}
</div>
</div>
);

View file

@ -19,15 +19,15 @@ module.exports = {
}
break;
case 'image/gif':
if (file.size > 50000000) {
if (file.size > 30000000) {
console.log('file was too big');
throw new Error('Sorry, GIFs are limited to 50 megabytes.');
throw new Error('Sorry, GIFs are limited to 30 megabytes.');
}
break;
case 'video/mp4':
if (file.size > 50000000) {
if (file.size > 20000000) {
console.log('file was too big');
throw new Error('Sorry, videos are limited to 50 megabytes.');
throw new Error('Sorry, videos are limited to 20 megabytes.');
}
break;
default:

View file

@ -5,9 +5,7 @@ const multipartMiddleware = multipart({uploadDir: files.uploadDirectory});
const db = require('../models');
const { claimNameIsAvailable, checkChannelAvailability, publish } = require('../controllers/publishController.js');
const { getClaimList, resolveUri, getClaim } = require('../helpers/lbryApi.js');
const { addGetResultsToFileData, createBasicPublishParams, createThumbnailPublishParams, parsePublishApiRequestBody, parsePublishApiRequestFiles, createFileData } = require('../helpers/publishHelpers.js');
const errorHandlers = require('../helpers/errorHandlers.js');
const { sendGAAnonymousPublishTiming, sendGAChannelPublishTiming } = require('../helpers/googleAnalytics.js');
const { authenticateUser } = require('../auth/authentication.js');