added flux to anonymous/channel select
This commit is contained in:
parent
66e1496a73
commit
67bf5b74f9
12 changed files with 242 additions and 175 deletions
|
@ -1,7 +1,10 @@
|
||||||
// export action types
|
// export action types
|
||||||
export const FILE_SELECTED = 'FILE_SELECTED';
|
export const FILE_SELECTED = 'FILE_SELECTED';
|
||||||
export const FILE_CLEAR = 'FILE_CLEAR';
|
export const FILE_CLEAR = 'FILE_CLEAR';
|
||||||
export const METADATA_UPDATE = 'TITLE_UPDATE';
|
export const METADATA_UPDATE = 'METADATA_UPDATE';
|
||||||
|
export const CLAIM_UPDATE = 'CLAIM_UPDATE';
|
||||||
|
export const CHANNEL_UPDATE = 'CHANNEL_UPDATE';
|
||||||
|
export const SET_PUBLISH_IN_CHANNEL = 'SET_PUBLISH_IN_CHANNEL';
|
||||||
|
|
||||||
// export action creators
|
// export action creators
|
||||||
export function selectFile (file) {
|
export function selectFile (file) {
|
||||||
|
@ -24,3 +27,26 @@ export function updateMetadata (name, value) {
|
||||||
value,
|
value,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function updateClaim (value) {
|
||||||
|
return {
|
||||||
|
type: CLAIM_UPDATE,
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function updateLoggedInChannel (name, shortId, longId) {
|
||||||
|
return {
|
||||||
|
type: CHANNEL_UPDATE,
|
||||||
|
name,
|
||||||
|
shortId,
|
||||||
|
longId,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function setPublishInChannel (value) {
|
||||||
|
return {
|
||||||
|
type: SET_PUBLISH_IN_CHANNEL,
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { setPublishInChannel } from '../actions';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
class AnonymousOrChannelSelect extends React.Component {
|
class AnonymousOrChannelSelect extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
|
@ -8,9 +10,9 @@ class AnonymousOrChannelSelect extends React.Component {
|
||||||
toggleAnonymousPublish (event) {
|
toggleAnonymousPublish (event) {
|
||||||
const value = event.target.value;
|
const value = event.target.value;
|
||||||
if (value === 'anonymous') {
|
if (value === 'anonymous') {
|
||||||
this.props.updateUploaderState('publishToChannel', false);
|
this.props.onPublishToChannelChange(false);
|
||||||
} else {
|
} else {
|
||||||
this.props.updateUploaderState('publishToChannel', true);
|
this.props.onPublishToChannelChange(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
|
@ -19,11 +21,11 @@ class AnonymousOrChannelSelect extends React.Component {
|
||||||
<div className="column column--10">
|
<div className="column column--10">
|
||||||
<form>
|
<form>
|
||||||
<div className="column column--3 column--med-10">
|
<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.publishToChannel} onChange={this.toggleAnonymousPublish}/>
|
<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>
|
<label className="label label--pointer" htmlFor="anonymous-radio">Anonymous</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="column column--7 column--med-10">
|
<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.publishToChannel} onChange={this.toggleAnonymousPublish}/>
|
<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>
|
<label className="label label--pointer" htmlFor="channel-radio">In a channel</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -33,4 +35,18 @@ class AnonymousOrChannelSelect extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = AnonymousOrChannelSelect;
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
publishInChannel: state.publishInChannel,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
onPublishToChannelChange: (value) => {
|
||||||
|
dispatch(setPublishInChannel(value));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(AnonymousOrChannelSelect);
|
||||||
|
|
|
@ -28,6 +28,11 @@ class ChannelSelector extends React.Component {
|
||||||
selectOption (option) {
|
selectOption (option) {
|
||||||
this.setState({optionState: option});
|
this.setState({optionState: option});
|
||||||
}
|
}
|
||||||
|
updateLoggedInChannelOutsideReact (channelName, channelClaimId, shortChannelId) {
|
||||||
|
// update anywhere on page that needs to be updated outside of this component
|
||||||
|
setUserCookies(channelName, channelClaimId, shortChannelId);
|
||||||
|
this.replaceChannelSelectionInNavBar(channelName);
|
||||||
|
}
|
||||||
replaceChannelSelectionInNavBar (loggedInChannel) {
|
replaceChannelSelectionInNavBar (loggedInChannel) {
|
||||||
// remove the old channel option
|
// remove the old channel option
|
||||||
const oldChannel = document.getElementById('nav-bar-channel-select-channel-option');
|
const oldChannel = document.getElementById('nav-bar-channel-select-channel-option');
|
||||||
|
@ -48,11 +53,6 @@ class ChannelSelector extends React.Component {
|
||||||
const navBarLoginLink = document.getElementById('nav-bar-login-link');
|
const navBarLoginLink = document.getElementById('nav-bar-login-link');
|
||||||
navBarLoginLink.style.display = 'none';
|
navBarLoginLink.style.display = 'none';
|
||||||
}
|
}
|
||||||
updateLoggedInChannelOutsideReact (channelName, channelClaimId, shortChannelId) {
|
|
||||||
// update anywhere on page that needs to be updated outside of this component
|
|
||||||
setUserCookies(channelName, channelClaimId, shortChannelId);
|
|
||||||
this.replaceChannelSelectionInNavBar(channelName);
|
|
||||||
}
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
|
||||||
class PreviewDropzone extends React.Component {
|
class PreviewDropzone extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
|
@ -39,4 +40,10 @@ class PreviewDropzone extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = PreviewDropzone;
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
file: state.file,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(PreviewDropzone);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
// import PropTypes from 'prop-types';
|
// import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { selectFile } from '../actions';
|
import { selectFile } from '../actions';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
@ -18,7 +17,6 @@ class PublishDropzone extends React.Component {
|
||||||
this.handleDragLeave = this.handleDragLeave.bind(this);
|
this.handleDragLeave = this.handleDragLeave.bind(this);
|
||||||
this.handleClick = this.handleClick.bind(this);
|
this.handleClick = this.handleClick.bind(this);
|
||||||
this.handleFileInput = this.handleFileInput.bind(this);
|
this.handleFileInput = this.handleFileInput.bind(this);
|
||||||
this.setClaimNameFromFileName = this.setClaimNameFromFileName.bind(this);
|
|
||||||
}
|
}
|
||||||
validateFile (file) {
|
validateFile (file) {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
|
@ -113,16 +111,9 @@ class PublishDropzone extends React.Component {
|
||||||
return this.setState({fileError: error.message});
|
return this.setState({fileError: error.message});
|
||||||
}
|
}
|
||||||
// stage it so it will be ready when the publish button is clicked
|
// stage it so it will be ready when the publish button is clicked
|
||||||
this.setClaimNameFromFileName(chosenFile.name);
|
|
||||||
this.props.onFileSelect(chosenFile);
|
this.props.onFileSelect(chosenFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setClaimNameFromFileName (fileName) {
|
|
||||||
console.log('setClaimNameFromFileName', fileName);
|
|
||||||
const fileNameWithoutEnding = fileName.substring(0, fileName.lastIndexOf('.'));
|
|
||||||
const cleanClaimName = this.props.cleanseInput(fileNameWithoutEnding);
|
|
||||||
this.props.updateUploaderState('claim', cleanClaimName);
|
|
||||||
}
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className="row row--tall flex-container--column">
|
<div className="row row--tall flex-container--column">
|
||||||
|
|
|
@ -7,8 +7,9 @@ import PublishThumbnailInput from './PublishThumbnailInput.jsx';
|
||||||
import PublishMetadataInputs from './PublishMetadataInputs.jsx';
|
import PublishMetadataInputs from './PublishMetadataInputs.jsx';
|
||||||
import AnonymousOrChannelSelect from './AnonymousOrChannelSelect.jsx';
|
import AnonymousOrChannelSelect from './AnonymousOrChannelSelect.jsx';
|
||||||
|
|
||||||
import { selectFile, clearFile } from '../actions';
|
import {selectFile, clearFile, updateLoggedInChannel} from '../actions';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { getCookie } from '../utils/cookies.js';
|
||||||
|
|
||||||
class PublishForm extends React.Component {
|
class PublishForm extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
|
@ -20,6 +21,14 @@ class PublishForm extends React.Component {
|
||||||
};
|
};
|
||||||
this.publish = this.publish.bind(this);
|
this.publish = this.publish.bind(this);
|
||||||
}
|
}
|
||||||
|
componentWillMount () {
|
||||||
|
// check for whether a channel is logged in
|
||||||
|
// if so, set the loggedInChannel to the channel name
|
||||||
|
const loggedInChannelName = getCookie('channel_name');
|
||||||
|
const loggedInChannelShortId = getCookie('short_channel_id');
|
||||||
|
const loggedInChannelLongId = getCookie('long_channel_id');
|
||||||
|
this.props.onChannelUpdate(loggedInChannelName, loggedInChannelShortId, loggedInChannelLongId);
|
||||||
|
}
|
||||||
publish () {
|
publish () {
|
||||||
// publish the asset
|
// publish the asset
|
||||||
}
|
}
|
||||||
|
@ -34,33 +43,16 @@ class PublishForm extends React.Component {
|
||||||
<div className="column column--5 column--sml-10" >
|
<div className="column column--5 column--sml-10" >
|
||||||
<div className="row row--padded">
|
<div className="row row--padded">
|
||||||
|
|
||||||
<PreviewDropzone
|
<PreviewDropzone />
|
||||||
file={this.props.file}
|
{ (this.props.fileType === 'video/mp4') && <PublishThumbnailInput /> }
|
||||||
/>
|
|
||||||
{ (this.props.file.type === 'video/mp4') &&
|
|
||||||
<PublishThumbnailInput
|
|
||||||
thumbnail={this.props.thumbnail}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="column column--5 column--sml-10 align-content-top">
|
<div className="column column--5 column--sml-10 align-content-top">
|
||||||
<div id="publish-active-area" className="row row--padded">
|
<div id="publish-active-area" className="row row--padded">
|
||||||
|
|
||||||
<PublishUrlInput
|
<PublishUrlInput />
|
||||||
fileName={this.props.file.name}
|
<AnonymousOrChannelSelect />
|
||||||
claim={this.props.claim}
|
|
||||||
publishToChannel={this.props.publishToChannel}
|
|
||||||
loggedInChannelName={this.props.loggedInChannelName}
|
|
||||||
loggedInChannelShortId={this.props.loggedInChannelShortId}
|
|
||||||
cleanseInput={this.props.cleanseInput}
|
|
||||||
updateUploaderState={this.props.updateUploaderState}
|
|
||||||
makeGetRequest={this.props.makeGetRequest}
|
|
||||||
/>
|
|
||||||
<AnonymousOrChannelSelect
|
|
||||||
publishToChannel={this.props.publishToChannel}
|
|
||||||
updateUploaderState={this.props.updateUploaderState}
|
|
||||||
/>
|
|
||||||
<ChannelSelector
|
<ChannelSelector
|
||||||
loggedInChannelName={this.props.loggedInChannelName}
|
loggedInChannelName={this.props.loggedInChannelName}
|
||||||
publishToChannel={this.props.publishToChannel}
|
publishToChannel={this.props.publishToChannel}
|
||||||
|
@ -96,13 +88,10 @@ class PublishForm extends React.Component {
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
return {
|
return {
|
||||||
loggedInChannelName : state.loggedInChannelName,
|
fileType : state.file.type,
|
||||||
loggedInChannelShortId: state.loggedInChannelShortId,
|
|
||||||
publishToChannel : state.publishToChannel,
|
|
||||||
file : state.file,
|
|
||||||
claim : state.claim,
|
claim : state.claim,
|
||||||
thumbnail : state.thumbnail,
|
thumbnail : state.thumbnail,
|
||||||
description : state.description,
|
description: state.description,
|
||||||
license : state.license,
|
license : state.license,
|
||||||
nsfw : state.nsfw,
|
nsfw : state.nsfw,
|
||||||
};
|
};
|
||||||
|
@ -116,7 +105,10 @@ const mapDispatchToProps = dispatch => {
|
||||||
onFileClear: () => {
|
onFileClear: () => {
|
||||||
dispatch(clearFile());
|
dispatch(clearFile());
|
||||||
},
|
},
|
||||||
|
onChannelUpdate: (name, shortId, longId) => {
|
||||||
|
dispatch(updateLoggedInChannel(name, shortId, longId));
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(PublishForm);
|
export default connect(mapStateToProps, mapDispatchToProps)(PublishForm);
|
||||||
|
|
|
@ -7,104 +7,13 @@ import {connect} from 'react-redux';
|
||||||
class PublishTool extends React.Component {
|
class PublishTool extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
// bind class methods with `this`
|
|
||||||
this.updateUploaderState = this.updateUploaderState.bind(this);
|
|
||||||
this.makeGetRequest = this.makeGetRequest.bind(this);
|
|
||||||
this.makePostRequest = this.makePostRequest.bind(this);
|
|
||||||
this.cleanseInput = this.cleanseInput.bind(this);
|
|
||||||
this.getCookie = this.getCookie.bind(this);
|
|
||||||
}
|
|
||||||
componentDidMount () {
|
|
||||||
// check for whether a channel is logged in
|
|
||||||
// if so, setState loggedInChannel to the channel name
|
|
||||||
const loggedInChannelName = this.getCookie('channel_name');
|
|
||||||
this.setState({loggedInChannelName})
|
|
||||||
const loggedInChannelShortId = this.getCookie('short_channel_id');
|
|
||||||
this.setState({loggedInChannelShortId});
|
|
||||||
}
|
|
||||||
updateUploaderState (name, value) {
|
|
||||||
console.log(`updateUploaderState ${name} ${value}`);
|
|
||||||
this.setState({[name]: value});
|
|
||||||
}
|
|
||||||
makeGetRequest (url) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let xhttp = new XMLHttpRequest();
|
|
||||||
xhttp.open('GET', url, true);
|
|
||||||
xhttp.responseType = 'json';
|
|
||||||
xhttp.onreadystatechange = () => {
|
|
||||||
if (xhttp.readyState === 4) {
|
|
||||||
if (xhttp.status === 200) {
|
|
||||||
resolve(xhttp.response);
|
|
||||||
} else if (xhttp.status === 401) {
|
|
||||||
reject('Wrong channel name or password');
|
|
||||||
} else {
|
|
||||||
reject('request failed with status:' + xhttp.status);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhttp.send();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
makePostRequest (url, params) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let xhttp = new XMLHttpRequest();
|
|
||||||
xhttp.open('POST', url, true);
|
|
||||||
xhttp.responseType = 'json';
|
|
||||||
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
|
||||||
xhttp.onreadystatechange = () => {
|
|
||||||
if (xhttp.readyState === 4) {
|
|
||||||
if (xhttp.status === 200) {
|
|
||||||
resolve(xhttp.response);
|
|
||||||
} else if (xhttp.status === 401) {
|
|
||||||
reject('Wrong channel name or password');
|
|
||||||
} else {
|
|
||||||
reject('request failed with status:' + xhttp.status);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhttp.send(params);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
cleanseInput (input) {
|
|
||||||
input = input.replace(/\s+/g, '-'); // replace spaces with dashes
|
|
||||||
input = input.replace(/[^A-Za-z0-9-]/g, ''); // remove all characters that are not A-Z, a-z, 0-9, or '-'
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
getCookie (cname) {
|
|
||||||
const name = cname + '=';
|
|
||||||
const decodedCookie = decodeURIComponent(document.cookie);
|
|
||||||
const ca = decodedCookie.split(';');
|
|
||||||
for (let i = 0; i < ca.length; i++) {
|
|
||||||
let c = ca[i];
|
|
||||||
while (c.charAt(0) === ' ') {
|
|
||||||
c = c.substring(1);
|
|
||||||
}
|
|
||||||
if (c.indexOf(name) === 0) {
|
|
||||||
return c.substring(name.length, c.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className="row row--tall flex-container--column">
|
<div className="row row--tall flex-container--column">
|
||||||
{ !this.props.file &&
|
{ !this.props.file && <PublishDropzone /> }
|
||||||
<PublishDropzone
|
{ this.props.file && <PublishForm /> }
|
||||||
updateUploaderState={this.updateUploaderState}
|
{ this.props.publishStatus && <PublishStatus /> }
|
||||||
cleanseInput={this.cleanseInput}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{ this.props.file &&
|
|
||||||
<PublishForm
|
|
||||||
updateUploaderState={this.updateUploaderState}
|
|
||||||
makeGetRequest={this.makeGetRequest}
|
|
||||||
makePostRequest={this.makePostRequest}
|
|
||||||
cleanseInput={this.cleanseInput}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{ this.props.publishStatus &&
|
|
||||||
<PublishStatus />
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -112,7 +21,8 @@ class PublishTool extends React.Component {
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
return {
|
return {
|
||||||
file: state.file,
|
file : state.file,
|
||||||
|
publishStatus: state.publishStatus,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { updateClaim } from '../actions';
|
||||||
function UrlMiddle ({publishToChannel, loggedInChannelName, loggedInChannelShortId}) {
|
import { connect } from 'react-redux';
|
||||||
if (publishToChannel) {
|
import { makeGetRequest } from '../utils/xhr.js';
|
||||||
if (loggedInChannelName) {
|
import UrlMiddle from './UrlMiddle.jsx';
|
||||||
return <span id="url-channel" className="url-text--secondary">{loggedInChannelName}:{loggedInChannelShortId} /</span>;
|
|
||||||
}
|
|
||||||
return <span id="url-channel-placeholder" className="url-text--secondary tooltip">@channel<span
|
|
||||||
className="tooltip-text">Select a channel below</span> /</span>;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<span id="url-no-channel-placeholder" className="url-text--secondary tooltip">xyz<span className="tooltip-text">This will be a random id</span> /</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class UrlChooser extends React.Component {
|
class UrlChooser extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
|
@ -22,19 +13,39 @@ class UrlChooser extends React.Component {
|
||||||
urlMiddle: null,
|
urlMiddle: null,
|
||||||
};
|
};
|
||||||
this.handleInput = this.handleInput.bind(this);
|
this.handleInput = this.handleInput.bind(this);
|
||||||
|
this.cleanseInput = this.cleanseInput.bind(this);
|
||||||
|
this.setClaimNameFromFileName = this.setClaimNameFromFileName.bind(this);
|
||||||
this.checkClaimIsAvailable = this.checkClaimIsAvailable.bind(this);
|
this.checkClaimIsAvailable = this.checkClaimIsAvailable.bind(this);
|
||||||
}
|
}
|
||||||
|
componentWillMount () {
|
||||||
|
if (!this.props.claim || this.props.claim === '') {
|
||||||
|
this.setClaimNameFromFileName();
|
||||||
|
}
|
||||||
|
}
|
||||||
handleInput (event) {
|
handleInput (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let value = event.target.value;
|
let value = event.target.value;
|
||||||
const name = event.target.name;
|
value = this.cleanseInput(value);
|
||||||
value = this.props.cleanseInput(value);
|
// update the state
|
||||||
this.props.updateUploaderState(name, value);
|
this.props.onClaimChange(value);
|
||||||
|
// check to make sure claim name is available
|
||||||
this.checkClaimIsAvailable(value);
|
this.checkClaimIsAvailable(value);
|
||||||
}
|
}
|
||||||
|
cleanseInput (input) {
|
||||||
|
input = input.replace(/\s+/g, '-'); // replace spaces with dashes
|
||||||
|
input = input.replace(/[^A-Za-z0-9-]/g, ''); // remove all characters that are not A-Z, a-z, 0-9, or '-'
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
setClaimNameFromFileName () {
|
||||||
|
const fileName = this.props.fileName;
|
||||||
|
console.log('setClaimNameFromFileName', fileName);
|
||||||
|
const fileNameWithoutEnding = fileName.substring(0, fileName.lastIndexOf('.'));
|
||||||
|
const cleanClaimName = this.cleanseInput(fileNameWithoutEnding);
|
||||||
|
this.props.onClaimChange(cleanClaimName);
|
||||||
|
}
|
||||||
checkClaimIsAvailable (claim) {
|
checkClaimIsAvailable (claim) {
|
||||||
const that = this;
|
const that = this;
|
||||||
this.props.makeGetRequest(`/api/claim-is-available/${claim}`)
|
makeGetRequest(`/api/claim-is-available/${claim}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
that.setState({'error': null});
|
that.setState({'error': null});
|
||||||
})
|
})
|
||||||
|
@ -58,9 +69,7 @@ class UrlChooser extends React.Component {
|
||||||
<UrlMiddle publishToChannel={this.props.publishToChannel} loggedInChannelName={this.props.loggedInChannelName} loggedInChannelShortId={this.props.loggedInChannelShortId}/>
|
<UrlMiddle publishToChannel={this.props.publishToChannel} loggedInChannelName={this.props.loggedInChannelName} loggedInChannelShortId={this.props.loggedInChannelShortId}/>
|
||||||
|
|
||||||
<input type="text" id="claim-name-input" className="input-text" name='claim' placeholder="your-url-here" onChange={this.handleInput} value={this.props.claim}/>
|
<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.state.error) && (
|
{ (this.props.claim && !this.state.error) && <span id="input-success-claim-name" className="info-message--success span--absolute">{'\u2713'}</span> }
|
||||||
<span id="input-success-claim-name" className="info-message--success span--absolute">{'\u2713'}</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -70,4 +79,22 @@ class UrlChooser extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = UrlChooser;
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
fileName : state.file.name,
|
||||||
|
loggedInChannelName : state.loggedInChannel.name,
|
||||||
|
loggedInChannelShortId: state.loggedInChannel.shortId,
|
||||||
|
publishToChannel : state.publishToChannel,
|
||||||
|
claim : state.claim,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
onClaimChange: (value) => {
|
||||||
|
dispatch(updateClaim(value));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(UrlChooser);
|
||||||
|
|
16
react/components/UrlMiddle.jsx
Normal file
16
react/components/UrlMiddle.jsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
function UrlMiddle ({publishToChannel, loggedInChannelName, loggedInChannelShortId}) {
|
||||||
|
if (publishToChannel) {
|
||||||
|
if (loggedInChannelName) {
|
||||||
|
return <span id="url-channel" className="url-text--secondary">{loggedInChannelName}:{loggedInChannelShortId} /</span>;
|
||||||
|
}
|
||||||
|
return <span id="url-channel-placeholder" className="url-text--secondary tooltip">@channel<span
|
||||||
|
className="tooltip-text">Select a channel below</span> /</span>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<span id="url-no-channel-placeholder" className="url-text--secondary tooltip">xyz<span className="tooltip-text">This will be a random id</span> /</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UrlMiddle;
|
|
@ -1,15 +1,22 @@
|
||||||
import {FILE_CLEAR, FILE_SELECTED, METADATA_UPDATE} from '../actions';
|
import {
|
||||||
|
CHANNEL_UPDATE, CLAIM_UPDATE, FILE_CLEAR, FILE_SELECTED, METADATA_UPDATE,
|
||||||
|
SET_PUBLISH_IN_CHANNEL,
|
||||||
|
} from '../actions';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
loggedInChannelName : null,
|
loggedInChannel: {
|
||||||
|
name : null,
|
||||||
|
shortId: null,
|
||||||
|
longId : null,
|
||||||
|
},
|
||||||
loggedInChannelShortId: null,
|
loggedInChannelShortId: null,
|
||||||
publishToChannel : false,
|
publishInChannel : false,
|
||||||
publishStatus : null,
|
publishStatus : null,
|
||||||
error : null,
|
error : null,
|
||||||
file : null,
|
file : null,
|
||||||
|
claim : '',
|
||||||
metadata : {
|
metadata : {
|
||||||
title : '',
|
title : '',
|
||||||
claim : '',
|
|
||||||
thumbnail : '',
|
thumbnail : '',
|
||||||
description: '',
|
description: '',
|
||||||
license : '',
|
license : '',
|
||||||
|
@ -35,7 +42,23 @@ export default function (state = initialState, action) {
|
||||||
metadata: {
|
metadata: {
|
||||||
[action.name]: action.value,
|
[action.name]: action.value,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
case CLAIM_UPDATE:
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
claim: action.value,
|
||||||
|
});
|
||||||
|
case CHANNEL_UPDATE:
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
loggedInChannel: {
|
||||||
|
name : action.name,
|
||||||
|
shortId: action.shortId,
|
||||||
|
longId : action.longId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
case SET_PUBLISH_IN_CHANNEL:
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
publishInChannel: action.value,
|
||||||
|
});
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
18
react/utils/cookies.js
Normal file
18
react/utils/cookies.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
module.exports = {
|
||||||
|
getCookie (cname) {
|
||||||
|
const name = cname + '=';
|
||||||
|
const decodedCookie = decodeURIComponent(document.cookie);
|
||||||
|
const ca = decodedCookie.split(';');
|
||||||
|
for (let i = 0; i < ca.length; i++) {
|
||||||
|
let c = ca[i];
|
||||||
|
while (c.charAt(0) === ' ') {
|
||||||
|
c = c.substring(1);
|
||||||
|
}
|
||||||
|
if (c.indexOf(name) === 0) {
|
||||||
|
return c.substring(name.length, c.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
41
react/utils/xhr.js
Normal file
41
react/utils/xhr.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
module.exports = {
|
||||||
|
makeGetRequest (url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.open('GET', url, true);
|
||||||
|
xhttp.responseType = 'json';
|
||||||
|
xhttp.onreadystatechange = () => {
|
||||||
|
if (xhttp.readyState === 4) {
|
||||||
|
if (xhttp.status === 200) {
|
||||||
|
resolve(xhttp.response);
|
||||||
|
} else if (xhttp.status === 401) {
|
||||||
|
reject('Wrong channel name or password');
|
||||||
|
} else {
|
||||||
|
reject('request failed with status:' + xhttp.status);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.send();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
makePostRequest (url, params) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.open('POST', url, true);
|
||||||
|
xhttp.responseType = 'json';
|
||||||
|
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||||
|
xhttp.onreadystatechange = () => {
|
||||||
|
if (xhttp.readyState === 4) {
|
||||||
|
if (xhttp.status === 200) {
|
||||||
|
resolve(xhttp.response);
|
||||||
|
} else if (xhttp.status === 401) {
|
||||||
|
reject('Wrong channel name or password');
|
||||||
|
} else {
|
||||||
|
reject('request failed with status:' + xhttp.status);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.send(params);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
Loading…
Reference in a new issue