Auto eslint fix
This commit is contained in:
@ -1,105 +1,114 @@
|
||||
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import Link from '../../components/Link'
|
||||
import ReactGA from 'react-ga'
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import ReactGA from 'react-ga';
|
||||
import Link from '../../components/Link';
|
||||
|
||||
import Modal from './Modal';
|
||||
import Icon from '../../components/Icon';
|
||||
import Thumbnail from '../../components/Thumbnail';
|
||||
import * as coreActions from '../../services/core/actions'
|
||||
import * as uiActions from '../../services/ui/actions'
|
||||
import * as mopidyActions from '../../services/mopidy/actions'
|
||||
import * as spotifyActions from '../../services/spotify/actions'
|
||||
import * as coreActions from '../../services/core/actions';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as mopidyActions from '../../services/mopidy/actions';
|
||||
import * as spotifyActions from '../../services/spotify/actions';
|
||||
import * as helpers from '../../helpers';
|
||||
|
||||
class AddToPlaylist extends React.Component{
|
||||
class AddToPlaylist extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
if (!this.props.spotify_library_playlists) {
|
||||
this.props.spotifyActions.getLibraryPlaylists();
|
||||
}
|
||||
|
||||
if (!this.props.spotify_library_playlists){
|
||||
this.props.spotifyActions.getLibraryPlaylists()
|
||||
}
|
||||
|
||||
if (!this.props.mopidy_library_playlists && this.props.mopidy_connected){
|
||||
this.props.mopidyActions.getLibraryPlaylists()
|
||||
}
|
||||
}
|
||||
if (!this.props.mopidy_library_playlists && this.props.mopidy_connected) {
|
||||
this.props.mopidyActions.getLibraryPlaylists();
|
||||
}
|
||||
}
|
||||
|
||||
playlistSelected(playlist_uri){
|
||||
this.props.coreActions.addTracksToPlaylist(playlist_uri, this.props.uris);
|
||||
window.history.back();
|
||||
}
|
||||
playlistSelected(playlist_uri) {
|
||||
this.props.coreActions.addTracksToPlaylist(playlist_uri, this.props.uris);
|
||||
window.history.back();
|
||||
}
|
||||
|
||||
render(){
|
||||
if (!this.props.playlists ) return <div className="empty">No editable playlists</div>
|
||||
var playlists = []
|
||||
for (var uri in this.props.playlists){
|
||||
if (this.props.playlists[uri].can_edit ) playlists.push(this.props.playlists[uri] )
|
||||
}
|
||||
render() {
|
||||
if (!this.props.playlists) return <div className="empty">No editable playlists</div>;
|
||||
let playlists = [];
|
||||
for (const uri in this.props.playlists) {
|
||||
if (this.props.playlists[uri].can_edit) playlists.push(this.props.playlists[uri]);
|
||||
}
|
||||
|
||||
playlists = helpers.sortItems(playlists, 'name')
|
||||
playlists = helpers.sortItems(playlists, 'name');
|
||||
|
||||
var loader = null
|
||||
if (this.props.spotify_library_playlists_status == 'running'){
|
||||
loader = (
|
||||
<div className='lazy-loader body-loader loading'>
|
||||
<div className="loader"></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
let loader = null;
|
||||
if (this.props.spotify_library_playlists_status == 'running') {
|
||||
loader = (
|
||||
<div className="lazy-loader body-loader loading">
|
||||
<div className="loader" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal className="modal--add-to-playlist">
|
||||
<h1>Add to playlist</h1>
|
||||
<h2 className="mid_grey-text">Select playlist to add {this.props.uris.length} track{this.props.uris.length>1?'s':null} to</h2>
|
||||
{playlists.length <= 0 ? <div className="no-results">No playlists available</div> : null}
|
||||
<div className="list small playlists">
|
||||
{
|
||||
playlists.map(playlist => {
|
||||
return (
|
||||
<div className="list__item" key={playlist.uri} onClick={ () => this.playlistSelected(playlist.uri) }>
|
||||
<Thumbnail images={playlist.images} size="small" />
|
||||
<h4 className="list__item__name">{ playlist.name }</h4>
|
||||
<ul className="list__item__details details">
|
||||
<li><Icon type="fontawesome" className="source" name={helpers.sourceIcon(playlist.uri)} /></li>
|
||||
<li>{ playlist.tracks_total ? <span className="mid_grey-text"> { playlist.tracks_total } tracks</span> : null }</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
return (
|
||||
<Modal className="modal--add-to-playlist">
|
||||
<h1>Add to playlist</h1>
|
||||
<h2 className="mid_grey-text">
|
||||
Select playlist to add
|
||||
{this.props.uris.length}
|
||||
{' '}
|
||||
track
|
||||
{this.props.uris.length > 1 ? 's' : null}
|
||||
{' '}
|
||||
to
|
||||
</h2>
|
||||
{playlists.length <= 0 ? <div className="no-results">No playlists available</div> : null}
|
||||
<div className="list small playlists">
|
||||
{
|
||||
playlists.map((playlist) => (
|
||||
<div className="list__item" key={playlist.uri} onClick={() => this.playlistSelected(playlist.uri)}>
|
||||
<Thumbnail images={playlist.images} size="small" />
|
||||
<h4 className="list__item__name">{ playlist.name }</h4>
|
||||
<ul className="list__item__details details">
|
||||
<li><Icon type="fontawesome" className="source" name={helpers.sourceIcon(playlist.uri)} /></li>
|
||||
<li>
|
||||
{ playlist.tracks_total ? (
|
||||
<span className="mid_grey-text">
|
||||
{ playlist.tracks_total }
|
||||
{' '}
|
||||
tracks
|
||||
</span>
|
||||
) : null }
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
{loader}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
{loader}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
uris: (ownProps.match.params.uris ? decodeURIComponent(ownProps.match.params.uris).split(',') : []),
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
mopidy_uri_schemes: state.mopidy.uri_schemes,
|
||||
mopidy_library_playlists: state.mopidy.library_playlists,
|
||||
mopidy_library_playlists_status: (state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
|
||||
spotify_library_playlists: state.spotify.library_playlists,
|
||||
spotify_library_playlists_status: (state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
|
||||
load_queue: state.ui.load_queue,
|
||||
me_id: (state.spotify.me ? state.spotify.me.id : false),
|
||||
playlists: state.core.playlists
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
uris: (ownProps.match.params.uris ? decodeURIComponent(ownProps.match.params.uris).split(',') : []),
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
mopidy_uri_schemes: state.mopidy.uri_schemes,
|
||||
mopidy_library_playlists: state.mopidy.library_playlists,
|
||||
mopidy_library_playlists_status: (state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.MOPIDY_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
|
||||
spotify_library_playlists: state.spotify.library_playlists,
|
||||
spotify_library_playlists_status: (state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR !== undefined ? state.ui.processes.SPOTIFY_GET_LIBRARY_PLAYLISTS_PROCESSOR.status : null),
|
||||
load_queue: state.ui.load_queue,
|
||||
me_id: (state.spotify.me ? state.spotify.me.id : false),
|
||||
playlists: state.core.playlists,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AddToPlaylist)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AddToPlaylist);
|
||||
|
||||
@ -1,104 +1,102 @@
|
||||
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import Link from '../../components/Link'
|
||||
import ReactGA from 'react-ga'
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import ReactGA from 'react-ga';
|
||||
import Link from '../../components/Link';
|
||||
|
||||
import Modal from './Modal';
|
||||
import Icon from '../../components/Icon';
|
||||
import * as coreActions from '../../services/core/actions'
|
||||
import * as uiActions from '../../services/ui/actions'
|
||||
import * as mopidyActions from '../../services/mopidy/actions'
|
||||
import * as spotifyActions from '../../services/spotify/actions'
|
||||
import * as coreActions from '../../services/core/actions';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as mopidyActions from '../../services/mopidy/actions';
|
||||
import * as spotifyActions from '../../services/spotify/actions';
|
||||
import * as helpers from '../../helpers';
|
||||
|
||||
class AddToQueue extends React.Component{
|
||||
class AddToQueue extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
uris: '',
|
||||
next: false,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {
|
||||
uris: '',
|
||||
next: false
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.uiActions.setWindowTitle('Add to queue');
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.props.uiActions.setWindowTitle("Add to queue");
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const uris = this.state.uris.split(',');
|
||||
this.props.mopidyActions.enqueueURIs(uris, null, this.state.next);
|
||||
window.history.back();
|
||||
}
|
||||
|
||||
handleSubmit(e){
|
||||
e.preventDefault();
|
||||
var uris = this.state.uris.split(',');
|
||||
this.props.mopidyActions.enqueueURIs(uris, null, this.state.next);
|
||||
window.history.back();
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Modal className="modal--add-to-queue">
|
||||
<h1>Add to queue</h1>
|
||||
<h2 className="mid_grey-text">Add a comma-separated list of URIs to the play queue. You must have the appropriate Mopidy backend enabled for each URI schema (eg spotify:, yt:).</h2>
|
||||
|
||||
render(){
|
||||
return (
|
||||
<Modal className="modal--add-to-queue">
|
||||
<h1>Add to queue</h1>
|
||||
<h2 className="mid_grey-text">Add a comma-separated list of URIs to the play queue. You must have the appropriate Mopidy backend enabled for each URI schema (eg spotify:, yt:).</h2>
|
||||
<form onSubmit={(e) => this.handleSubmit(e)}>
|
||||
<div className="field text">
|
||||
<div className="name">URI(s)</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ uris: e.target.value })}
|
||||
value={this.state.uris}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form onSubmit={e => this.handleSubmit(e)}>
|
||||
<div className="field text">
|
||||
<div className="name">URI(s)</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={e => this.setState({uris: e.target.value})}
|
||||
value={this.state.uris} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field radio white">
|
||||
<div className="name">
|
||||
<div className="field radio white">
|
||||
<div className="name">
|
||||
Position
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="next"
|
||||
checked={!this.state.next}
|
||||
onChange={e => this.setState({next: false})} />
|
||||
<span className="label">End</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="next"
|
||||
checked={this.state.next}
|
||||
onChange={e => this.setState({next: true})} />
|
||||
<span className="label">After current track</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="next"
|
||||
checked={!this.state.next}
|
||||
onChange={(e) => this.setState({ next: false })}
|
||||
/>
|
||||
<span className="label">End</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="next"
|
||||
checked={this.state.next}
|
||||
onChange={(e) => this.setState({ next: true })}
|
||||
/>
|
||||
<span className="label">After current track</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="actions centered-text">
|
||||
<button type="submit" className="button button--primary button--large">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
<div className="actions centered-text">
|
||||
<button type="submit" className="button button--primary button--large">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
playlist: (state.core.playlists[ownProps.match.params.uri] !== undefined ? state.core.playlists[ownProps.match.params.uri] : null),
|
||||
playlists: state.core.playlists
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
playlist: (state.core.playlists[ownProps.match.params.uri] !== undefined ? state.core.playlists[ownProps.match.params.uri] : null),
|
||||
playlists: state.core.playlists,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AddToQueue)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AddToQueue);
|
||||
|
||||
@ -1,176 +1,177 @@
|
||||
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import Link from '../../components/Link'
|
||||
import ReactGA from 'react-ga'
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import ReactGA from 'react-ga';
|
||||
import Link from '../../components/Link';
|
||||
|
||||
import Modal from './Modal';
|
||||
import Icon from '../../components/Icon';
|
||||
import * as coreActions from '../../services/core/actions'
|
||||
import * as uiActions from '../../services/ui/actions'
|
||||
import * as coreActions from '../../services/core/actions';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as helpers from '../../helpers';
|
||||
|
||||
class CreatePlaylist extends React.Component{
|
||||
class CreatePlaylist extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
name: '',
|
||||
description: '',
|
||||
scheme: 'spotify',
|
||||
is_public: true,
|
||||
is_collaborative: false,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {
|
||||
name: '',
|
||||
description: '',
|
||||
scheme: 'spotify',
|
||||
is_public: true,
|
||||
is_collaborative: false
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.uiActions.setWindowTitle('Create playlist');
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.props.uiActions.setWindowTitle("Create playlist");
|
||||
}
|
||||
createPlaylist(e) {
|
||||
e.preventDefault();
|
||||
|
||||
createPlaylist(e){
|
||||
e.preventDefault();
|
||||
if (!this.state.name || this.state.name == '') {
|
||||
this.setState({ error: 'Name is required' });
|
||||
return false;
|
||||
}
|
||||
this.props.coreActions.createPlaylist(
|
||||
this.state.scheme,
|
||||
this.state.name,
|
||||
this.state.description,
|
||||
this.state.is_public,
|
||||
this.state.is_collaborative,
|
||||
);
|
||||
window.history.back();
|
||||
|
||||
if (!this.state.name || this.state.name == ''){
|
||||
this.setState({error: 'Name is required'})
|
||||
return false
|
||||
} else {
|
||||
this.props.coreActions.createPlaylist(
|
||||
this.state.scheme,
|
||||
this.state.name,
|
||||
this.state.description,
|
||||
this.state.is_public,
|
||||
this.state.is_collaborative
|
||||
);
|
||||
window.history.back();
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
renderFields(){
|
||||
switch (this.state.scheme){
|
||||
renderFields() {
|
||||
switch (this.state.scheme) {
|
||||
case 'spotify':
|
||||
return (
|
||||
<div>
|
||||
<div className="field text">
|
||||
<div className="name">Name</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ name: e.target.value })}
|
||||
value={this.state.name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
case 'spotify':
|
||||
return (
|
||||
<div>
|
||||
<div className="field text">
|
||||
<div className="name">Name</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={ e => this.setState({ name: e.target.value })}
|
||||
value={ this.state.name } />
|
||||
</div>
|
||||
</div>
|
||||
<div className="field text">
|
||||
<div className="name">Description</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ description: e.target.value })}
|
||||
|
||||
<div className="field text">
|
||||
<div className="name">Description</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={ e => this.setState({ description: e.target.value })}
|
||||
|
||||
value={ this.state.description } />
|
||||
</div>
|
||||
</div>
|
||||
value={this.state.description}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field checkbox white">
|
||||
<div className="name">
|
||||
<div className="field checkbox white">
|
||||
<div className="name">
|
||||
Options
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="is_public"
|
||||
checked={ this.state.is_public }
|
||||
onChange={ e => this.setState({ is_public: !this.state.is_public })} />
|
||||
<span className="label">Public</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="is_collaborative"
|
||||
checked={ this.state.is_collaborative }
|
||||
onChange={ e => this.setState({ is_collaborative: !this.state.is_collaborative })} />
|
||||
<span className="label">Collaborative</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="is_public"
|
||||
checked={this.state.is_public}
|
||||
onChange={(e) => this.setState({ is_public: !this.state.is_public })}
|
||||
/>
|
||||
<span className="label">Public</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="is_collaborative"
|
||||
checked={this.state.is_collaborative}
|
||||
onChange={(e) => this.setState({ is_collaborative: !this.state.is_collaborative })}
|
||||
/>
|
||||
<span className="label">Collaborative</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
default:
|
||||
return (
|
||||
<div>
|
||||
<div className="field text">
|
||||
<div className="name">Name</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={ e => this.setState({ name: e.target.value })}
|
||||
value={ this.state.name } />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return (
|
||||
<div>
|
||||
<div className="field text">
|
||||
<div className="name">Name</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ name: e.target.value })}
|
||||
value={this.state.name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<Modal className="modal--create-playlist">
|
||||
<h1>Create playlist</h1>
|
||||
<form onSubmit={(e) => this.createPlaylist(e)}>
|
||||
render() {
|
||||
return (
|
||||
<Modal className="modal--create-playlist">
|
||||
<h1>Create playlist</h1>
|
||||
<form onSubmit={(e) => this.createPlaylist(e)}>
|
||||
|
||||
<div className="field radio white">
|
||||
<div className="name">
|
||||
<div className="field radio white">
|
||||
<div className="name">
|
||||
Provider
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="scheme"
|
||||
value="spotify"
|
||||
checked={ this.state.scheme == 'spotify' }
|
||||
onChange={ e => this.setState({ scheme: e.target.value })} />
|
||||
<span className="label">Spotify</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="scheme"
|
||||
value="m3u"
|
||||
checked={ this.state.scheme == 'm3u' }
|
||||
onChange={ e => this.setState({ scheme: e.target.value })} />
|
||||
<span className="label">Mopidy</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.renderFields()}
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="scheme"
|
||||
value="spotify"
|
||||
checked={this.state.scheme == 'spotify'}
|
||||
onChange={(e) => this.setState({ scheme: e.target.value })}
|
||||
/>
|
||||
<span className="label">Spotify</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="scheme"
|
||||
value="m3u"
|
||||
checked={this.state.scheme == 'm3u'}
|
||||
onChange={(e) => this.setState({ scheme: e.target.value })}
|
||||
/>
|
||||
<span className="label">Mopidy</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="actions centered-text">
|
||||
<button type="submit" className="button button--primary button--large">Create playlist</button>
|
||||
</div>
|
||||
{this.renderFields()}
|
||||
|
||||
</form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
<div className="actions centered-text">
|
||||
<button type="submit" className="button button--primary button--large">Create playlist</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {}
|
||||
}
|
||||
const mapStateToProps = (state, ownProps) => ({});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch)
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(CreatePlaylist)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(CreatePlaylist);
|
||||
|
||||
@ -15,240 +15,242 @@ import * as pusherActions from '../../services/pusher/actions';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as helpers from '../../helpers';
|
||||
|
||||
class EditCommand extends React.Component{
|
||||
class EditCommand extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
id: helpers.generateGuid(),
|
||||
icon: 'power_settings_new',
|
||||
name: '',
|
||||
colour: '',
|
||||
url: `https://${window.location.hostname}/broadlink/sendCommand/power/`,
|
||||
method: 'GET',
|
||||
post_data: '',
|
||||
additional_headers: '',
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {
|
||||
id: helpers.generateGuid(),
|
||||
icon: 'power_settings_new',
|
||||
name: '',
|
||||
colour: '',
|
||||
url: "https://"+window.location.hostname+"/broadlink/sendCommand/power/",
|
||||
method: 'GET',
|
||||
post_data: "",
|
||||
additional_headers: ""
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
if (this.props.command) {
|
||||
this.props.uiActions.setWindowTitle('Edit command');
|
||||
this.setState(this.props.command);
|
||||
} else {
|
||||
this.props.uiActions.setWindowTitle('Create command');
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
if (this.props.command){
|
||||
this.props.uiActions.setWindowTitle("Edit command");
|
||||
this.setState(this.props.command);
|
||||
} else {
|
||||
this.props.uiActions.setWindowTitle("Create command");
|
||||
}
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
handleSubmit(e){
|
||||
e.preventDefault();
|
||||
this.props.pusherActions.setCommand(this.state);
|
||||
|
||||
this.props.pusherActions.setCommand(this.state);
|
||||
window.history.back();
|
||||
|
||||
window.history.back();
|
||||
// A bit hacky, but wait for a moment to allow the back navigation
|
||||
// and then scroll down to our commands list
|
||||
setTimeout(() => {
|
||||
helpers.scrollTo('#commands-setup');
|
||||
},
|
||||
10);
|
||||
|
||||
// A bit hacky, but wait for a moment to allow the back navigation
|
||||
// and then scroll down to our commands list
|
||||
setTimeout(() => {
|
||||
helpers.scrollTo("#commands-setup");
|
||||
},
|
||||
10
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
handleDelete(e) {
|
||||
this.props.pusherActions.removeCommand(this.state.id);
|
||||
window.history.back();
|
||||
|
||||
handleDelete(e){
|
||||
this.props.pusherActions.removeCommand(this.state.id);
|
||||
window.history.back();
|
||||
// A bit hacky, but wait for a moment to allow the back navigation
|
||||
// and then scroll down to our commands list
|
||||
setTimeout(() => {
|
||||
helpers.scrollTo('#commands-setup');
|
||||
},
|
||||
10);
|
||||
}
|
||||
|
||||
// A bit hacky, but wait for a moment to allow the back navigation
|
||||
// and then scroll down to our commands list
|
||||
setTimeout(() => {
|
||||
helpers.scrollTo("#commands-setup");
|
||||
},
|
||||
10
|
||||
);
|
||||
}
|
||||
render() {
|
||||
const icons = [
|
||||
'power_settings_new',
|
||||
'eject',
|
||||
'grade',
|
||||
'query_builder',
|
||||
'settings_input_component',
|
||||
'settings_input_hdmi',
|
||||
'settings_input_svideo',
|
||||
'forward_5',
|
||||
'forward_10',
|
||||
'forward_30',
|
||||
'replay',
|
||||
'replay_5',
|
||||
'replay_10',
|
||||
'replay_30',
|
||||
'skip_next',
|
||||
'skip_previous',
|
||||
'play_arrow',
|
||||
'pause',
|
||||
'stop',
|
||||
'shuffle',
|
||||
'snooze',
|
||||
'volume_off',
|
||||
'volume_down',
|
||||
'volume_up',
|
||||
'arrow_left',
|
||||
'arrow_drop_up',
|
||||
'arrow_right',
|
||||
'arrow_drop_down',
|
||||
'done',
|
||||
'done_all',
|
||||
'add',
|
||||
'remove',
|
||||
'clear',
|
||||
'cast',
|
||||
'speaker',
|
||||
'speaker_group',
|
||||
'audiotrack',
|
||||
'videogame_asset',
|
||||
'computer',
|
||||
'tv',
|
||||
];
|
||||
|
||||
render(){
|
||||
|
||||
var icons = [
|
||||
"power_settings_new",
|
||||
"eject",
|
||||
"grade",
|
||||
"query_builder",
|
||||
"settings_input_component",
|
||||
"settings_input_hdmi",
|
||||
"settings_input_svideo",
|
||||
"forward_5",
|
||||
"forward_10",
|
||||
"forward_30",
|
||||
"replay",
|
||||
"replay_5",
|
||||
"replay_10",
|
||||
"replay_30",
|
||||
"skip_next",
|
||||
"skip_previous",
|
||||
"play_arrow",
|
||||
"pause",
|
||||
"stop",
|
||||
"shuffle",
|
||||
"snooze",
|
||||
"volume_off",
|
||||
"volume_down",
|
||||
"volume_up",
|
||||
"arrow_left",
|
||||
"arrow_drop_up",
|
||||
"arrow_right",
|
||||
"arrow_drop_down",
|
||||
"done",
|
||||
"done_all",
|
||||
"add",
|
||||
"remove",
|
||||
"clear",
|
||||
"cast",
|
||||
"speaker",
|
||||
"speaker_group",
|
||||
"audiotrack",
|
||||
"videogame_asset",
|
||||
"computer",
|
||||
"tv"
|
||||
];
|
||||
|
||||
return (
|
||||
<Modal className="modal--create-command">
|
||||
<h1>{this.props.command ? "Edit" : "Create"} command</h1>
|
||||
<form onSubmit={(e) => this.handleSubmit(e)}>
|
||||
|
||||
<div className="field textarea white">
|
||||
<div className="name">
|
||||
Name
|
||||
</div>
|
||||
<div className="input">
|
||||
<TextField
|
||||
name="name"
|
||||
value={this.state.name}
|
||||
onChange={value => this.setState({ name: value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field radio white">
|
||||
<div className="name">
|
||||
Colour
|
||||
</div>
|
||||
<div className="input">
|
||||
<ColourField
|
||||
colour={this.state.colour}
|
||||
onChange={colour => this.setState({colour: colour})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field radio white">
|
||||
<div className="name">
|
||||
Icon
|
||||
</div>
|
||||
<div className="input">
|
||||
<IconField
|
||||
icon={this.state.icon}
|
||||
icons={icons}
|
||||
onChange={icon => this.setState({icon: icon})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field textarea white">
|
||||
<div className="name">
|
||||
URL
|
||||
</div>
|
||||
<div className="input">
|
||||
<TextField
|
||||
name="url"
|
||||
value={this.state.url}
|
||||
onChange={value => this.setState({ url: value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field radio white">
|
||||
<div className="name">
|
||||
Method
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="method"
|
||||
value="GET"
|
||||
checked={ this.state.method == 'GET' }
|
||||
onChange={ e => this.setState({ method: e.target.value })} />
|
||||
<span className="label">GET</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="method"
|
||||
value="POST"
|
||||
checked={ this.state.method == 'POST' }
|
||||
onChange={ e => this.setState({ method: e.target.value })} />
|
||||
<span className="label">POST</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.state.method == 'POST' && <div className="field textarea white">
|
||||
<div className="name">
|
||||
Data
|
||||
</div>
|
||||
<div className="input">
|
||||
<textarea
|
||||
name="command"
|
||||
value={this.state.post_data}
|
||||
onChange={ e => this.setState({ post_data: e.target.value })}>
|
||||
</textarea>
|
||||
</div>
|
||||
</div>}
|
||||
return (
|
||||
<Modal className="modal--create-command">
|
||||
<h1>
|
||||
{this.props.command ? 'Edit' : 'Create'}
|
||||
{' '}
|
||||
command
|
||||
</h1>
|
||||
<form onSubmit={(e) => this.handleSubmit(e)}>
|
||||
|
||||
<div className="field textarea white">
|
||||
<div className="name">
|
||||
<div className="name">
|
||||
Name
|
||||
</div>
|
||||
<div className="input">
|
||||
<TextField
|
||||
name="name"
|
||||
value={this.state.name}
|
||||
onChange={(value) => this.setState({ name: value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field radio white">
|
||||
<div className="name">
|
||||
Colour
|
||||
</div>
|
||||
<div className="input">
|
||||
<ColourField
|
||||
colour={this.state.colour}
|
||||
onChange={(colour) => this.setState({ colour })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field radio white">
|
||||
<div className="name">
|
||||
Icon
|
||||
</div>
|
||||
<div className="input">
|
||||
<IconField
|
||||
icon={this.state.icon}
|
||||
icons={icons}
|
||||
onChange={(icon) => this.setState({ icon })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field textarea white">
|
||||
<div className="name">
|
||||
URL
|
||||
</div>
|
||||
<div className="input">
|
||||
<TextField
|
||||
name="url"
|
||||
value={this.state.url}
|
||||
onChange={(value) => this.setState({ url: value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field radio white">
|
||||
<div className="name">
|
||||
Method
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="method"
|
||||
value="GET"
|
||||
checked={this.state.method == 'GET'}
|
||||
onChange={(e) => this.setState({ method: e.target.value })}
|
||||
/>
|
||||
<span className="label">GET</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="method"
|
||||
value="POST"
|
||||
checked={this.state.method == 'POST'}
|
||||
onChange={(e) => this.setState({ method: e.target.value })}
|
||||
/>
|
||||
<span className="label">POST</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.state.method == 'POST' && (
|
||||
<div className="field textarea white">
|
||||
<div className="name">
|
||||
Data
|
||||
</div>
|
||||
<div className="input">
|
||||
<textarea
|
||||
name="command"
|
||||
value={this.state.post_data}
|
||||
onChange={(e) => this.setState({ post_data: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="field textarea white">
|
||||
<div className="name">
|
||||
Additional Headers
|
||||
</div>
|
||||
<div className="input">
|
||||
<textarea
|
||||
name="headers"
|
||||
value={this.state.additional_headers}
|
||||
onChange={ e => this.setState({ additional_headers: e.target.value })}>
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="input">
|
||||
<textarea
|
||||
name="headers"
|
||||
value={this.state.additional_headers}
|
||||
onChange={(e) => this.setState({ additional_headers: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="actions centered-text">
|
||||
{this.props.command ? <button type="button" className="button button--destructive button--large" onClick={e => this.handleDelete(e)}>Delete</button> : null}
|
||||
<button type="submit" className="button button--primary button--large">Save</button>
|
||||
</div>
|
||||
<div className="actions centered-text">
|
||||
{this.props.command ? <button type="button" className="button button--destructive button--large" onClick={(e) => this.handleDelete(e)}>Delete</button> : null}
|
||||
<button type="submit" className="button button--primary button--large">Save</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
var id = ownProps.match.params.id;
|
||||
return {
|
||||
id: id,
|
||||
command: (id && state.pusher.commands && state.pusher.commands[id] !== undefined ? state.pusher.commands[id] : null)
|
||||
}
|
||||
}
|
||||
const { id } = ownProps.match.params;
|
||||
return {
|
||||
id,
|
||||
command: (id && state.pusher.commands && state.pusher.commands[id] !== undefined ? state.pusher.commands[id] : null),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
pusherActions: bindActionCreators(pusherActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch)
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
pusherActions: bindActionCreators(pusherActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditCommand)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditCommand);
|
||||
|
||||
@ -1,242 +1,236 @@
|
||||
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import Link from '../../components/Link'
|
||||
import ReactGA from 'react-ga'
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import ReactGA from 'react-ga';
|
||||
import Link from '../../components/Link';
|
||||
|
||||
import Modal from './Modal';
|
||||
import Icon from '../../components/Icon';
|
||||
import * as coreActions from '../../services/core/actions'
|
||||
import * as uiActions from '../../services/ui/actions'
|
||||
import * as mopidyActions from '../../services/mopidy/actions'
|
||||
import * as spotifyActions from '../../services/spotify/actions'
|
||||
import * as coreActions from '../../services/core/actions';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as mopidyActions from '../../services/mopidy/actions';
|
||||
import * as spotifyActions from '../../services/spotify/actions';
|
||||
import * as helpers from '../../helpers';
|
||||
|
||||
class EditPlaylist extends React.Component{
|
||||
class EditPlaylist extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
error: null,
|
||||
name: '',
|
||||
description: '',
|
||||
image: null,
|
||||
public: false,
|
||||
collaborative: false,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {
|
||||
error: null,
|
||||
name: '',
|
||||
description: '',
|
||||
image: null,
|
||||
public: false,
|
||||
collaborative: false
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.uiActions.setWindowTitle('Edit playlist');
|
||||
|
||||
componentDidMount(){
|
||||
if (this.props.playlist) {
|
||||
this.setState({
|
||||
name: this.props.playlist.name,
|
||||
description: this.props.playlist.description,
|
||||
public: (this.props.playlist.public == true),
|
||||
collaborative: (this.props.playlist.collaborative == true),
|
||||
});
|
||||
} else {
|
||||
switch (helpers.uriSource(this.props.uri)) {
|
||||
case 'spotify':
|
||||
this.props.spotifyActions.getPlaylist(this.props.uri);
|
||||
this.props.spotifyActions.following(this.props.uri);
|
||||
break;
|
||||
|
||||
this.props.uiActions.setWindowTitle("Edit playlist");
|
||||
default:
|
||||
if (this.props.mopidy_connected) {
|
||||
this.props.mopidyActions.getPlaylist(this.props.uri);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.props.playlist){
|
||||
this.setState({
|
||||
name: this.props.playlist.name,
|
||||
description: this.props.playlist.description,
|
||||
public: (this.props.playlist.public == true),
|
||||
collaborative: (this.props.playlist.collaborative == true)
|
||||
});
|
||||
} else {
|
||||
switch (helpers.uriSource(this.props.uri)){
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Playlist just loaded
|
||||
if (!this.props.playlist && nextProps.playlist) {
|
||||
this.setState({
|
||||
name: nextProps.playlist.name,
|
||||
description: nextProps.playlist.description,
|
||||
public: (nextProps.playlist.public == true),
|
||||
collaborative: (nextProps.playlist.collaborative == true),
|
||||
});
|
||||
|
||||
case 'spotify':
|
||||
this.props.spotifyActions.getPlaylist(this.props.uri);
|
||||
this.props.spotifyActions.following(this.props.uri);
|
||||
break
|
||||
// Mopidy just connected, and we don't have the playlist yet
|
||||
} else if (this.props.mopidy_connected != nextProps.mopidy_connected && !nextProps.playlist) {
|
||||
this.props.mopidyActions.getPlaylist(this.props.uri);
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
if (this.props.mopidy_connected){
|
||||
this.props.mopidyActions.getPlaylist(this.props.uri);
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
savePlaylist(e) {
|
||||
e.preventDefault();
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
if (!this.state.name || this.state.name == '') {
|
||||
this.setState({ error: 'Name is required' });
|
||||
return false;
|
||||
}
|
||||
this.props.coreActions.savePlaylist(
|
||||
this.props.uri,
|
||||
this.state.name,
|
||||
this.state.description,
|
||||
this.state.public,
|
||||
this.state.collaborative,
|
||||
this.state.image,
|
||||
);
|
||||
window.history.back();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Playlist just loaded
|
||||
if (!this.props.playlist && nextProps.playlist){
|
||||
this.setState({
|
||||
name: nextProps.playlist.name,
|
||||
description: nextProps.playlist.description,
|
||||
public: (nextProps.playlist.public == true),
|
||||
collaborative: (nextProps.playlist.collaborative == true)
|
||||
});
|
||||
setImage(e) {
|
||||
const self = this;
|
||||
|
||||
// Mopidy just connected, and we don't have the playlist yet
|
||||
} else if (this.props.mopidy_connected != nextProps.mopidy_connected && !nextProps.playlist){
|
||||
this.props.mopidyActions.getPlaylist(this.props.uri);
|
||||
}
|
||||
}
|
||||
// Create a file-reader to import the selected image as a base64 string
|
||||
const file_reader = new FileReader();
|
||||
|
||||
savePlaylist(e){
|
||||
e.preventDefault();
|
||||
|
||||
if (!this.state.name || this.state.name == ''){
|
||||
this.setState({error: 'Name is required'})
|
||||
return false
|
||||
} else {
|
||||
this.props.coreActions.savePlaylist(
|
||||
this.props.uri,
|
||||
this.state.name,
|
||||
this.state.description,
|
||||
this.state.public,
|
||||
this.state.collaborative,
|
||||
this.state.image
|
||||
);
|
||||
window.history.back();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
setImage(e){
|
||||
var self = this;
|
||||
|
||||
// Create a file-reader to import the selected image as a base64 string
|
||||
var file_reader = new FileReader();
|
||||
|
||||
// Once the image is loaded, convert the result
|
||||
file_reader.addEventListener("load", function(e){
|
||||
var image_base64 = e.target.result.replace('data:image/jpeg;base64,','');
|
||||
self.setState({image: image_base64});
|
||||
});
|
||||
|
||||
// This calls the filereader to load the file
|
||||
file_reader.readAsDataURL(e.target.files[0]);
|
||||
}
|
||||
file_reader.addEventListener('load', (e) => {
|
||||
const image_base64 = e.target.result.replace('data:image/jpeg;base64,', '');
|
||||
self.setState({ image: image_base64 });
|
||||
});
|
||||
|
||||
renderFields(){
|
||||
switch (helpers.uriSource(this.props.uri)){
|
||||
// This calls the filereader to load the file
|
||||
file_reader.readAsDataURL(e.target.files[0]);
|
||||
}
|
||||
|
||||
case 'spotify':
|
||||
return (
|
||||
<div>
|
||||
<div className="field text">
|
||||
<div className="name">Name</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={ e => this.setState({ name: e.target.value })}
|
||||
value={ this.state.name }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field text">
|
||||
<div className="name">Description</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={ e => this.setState({ description: e.target.value })}
|
||||
value={ this.state.description }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field file">
|
||||
<div className="name">Cover image</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="file"
|
||||
placeholder="Leave empty to keep existing image"
|
||||
onChange={e => this.setImage(e)}
|
||||
/>
|
||||
<div className="description">
|
||||
renderFields() {
|
||||
switch (helpers.uriSource(this.props.uri)) {
|
||||
case 'spotify':
|
||||
return (
|
||||
<div>
|
||||
<div className="field text">
|
||||
<div className="name">Name</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ name: e.target.value })}
|
||||
value={this.state.name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field text">
|
||||
<div className="name">Description</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ description: e.target.value })}
|
||||
value={this.state.description}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field file">
|
||||
<div className="name">Cover image</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="file"
|
||||
placeholder="Leave empty to keep existing image"
|
||||
onChange={(e) => this.setImage(e)}
|
||||
/>
|
||||
<div className="description">
|
||||
JPEG only, 256kB max. Leave empty to keep cover image unchanged.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field checkbox white">
|
||||
<div className="name">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field checkbox white">
|
||||
<div className="name">
|
||||
Options
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="playlist_private"
|
||||
checked={ this.state.public }
|
||||
onChange={ e => this.setState({ public: !this.state.public })} />
|
||||
<span className="label">Public</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="collaborative"
|
||||
checked={ this.state.collaborative }
|
||||
onChange={ e => this.setState({ collaborative: !this.state.collaborative })} />
|
||||
<span className="label">Collaborative</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
break
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="playlist_private"
|
||||
checked={this.state.public}
|
||||
onChange={(e) => this.setState({ public: !this.state.public })}
|
||||
/>
|
||||
<span className="label">Public</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="collaborative"
|
||||
checked={this.state.collaborative}
|
||||
onChange={(e) => this.setState({ collaborative: !this.state.collaborative })}
|
||||
/>
|
||||
<span className="label">Collaborative</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (
|
||||
<div>
|
||||
<div className="field text">
|
||||
<div className="name">Name</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={ e => this.setState({ name: e.target.value })}
|
||||
value={ this.state.name } />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return (
|
||||
<div>
|
||||
<div className="field text">
|
||||
<div className="name">Name</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ name: e.target.value })}
|
||||
value={this.state.name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<Modal className="modal--edit-playlist">
|
||||
<h1>Edit playlist</h1>
|
||||
{this.state.error ? <h3 className="red-text">{this.state.error}</h3> : null}
|
||||
<form onSubmit={(e) => this.savePlaylist(e)}>
|
||||
render() {
|
||||
return (
|
||||
<Modal className="modal--edit-playlist">
|
||||
<h1>Edit playlist</h1>
|
||||
{this.state.error ? <h3 className="red-text">{this.state.error}</h3> : null}
|
||||
<form onSubmit={(e) => this.savePlaylist(e)}>
|
||||
|
||||
{this.renderFields()}
|
||||
{this.renderFields()}
|
||||
|
||||
<div className="actions centered-text">
|
||||
<button type="submit" className="button button--primary button--large">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
<div className="actions centered-text">
|
||||
<button type="submit" className="button button--primary button--large">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
// Decode the URI, and then re-encode selected characters
|
||||
// This is needed as Mopidy encodes *some* characters in playlist URIs (but not other characters)
|
||||
// We need to retain ":" because this a reserved URI separator
|
||||
let uri = decodeURIComponent(ownProps.match.params.uri);
|
||||
uri = uri.replace(/\s/g, '%20'); // space
|
||||
uri = uri.replace(/\[/g, '%5B'); // [
|
||||
uri = uri.replace(/\]/g, '%5D'); // ]
|
||||
uri = uri.replace(/\(/g, '%28'); // (
|
||||
uri = uri.replace(/\)/g, '%29'); // )
|
||||
uri = uri.replace(/\#/g, '%23'); // #
|
||||
|
||||
// Decode the URI, and then re-encode selected characters
|
||||
// This is needed as Mopidy encodes *some* characters in playlist URIs (but not other characters)
|
||||
// We need to retain ":" because this a reserved URI separator
|
||||
var uri = decodeURIComponent(ownProps.match.params.uri);
|
||||
uri = uri.replace(/\s/g, '%20'); // space
|
||||
uri = uri.replace(/\[/g, '%5B'); // [
|
||||
uri = uri.replace(/\]/g, '%5D'); // ]
|
||||
uri = uri.replace(/\(/g, '%28'); // (
|
||||
uri = uri.replace(/\)/g, '%29'); // )
|
||||
uri = uri.replace(/\#/g, '%23'); // #
|
||||
|
||||
return {
|
||||
uri: uri,
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
playlist: (state.core.playlists[uri] !== undefined ? state.core.playlists[uri] : null),
|
||||
playlists: state.core.playlists
|
||||
}
|
||||
}
|
||||
return {
|
||||
uri,
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
playlist: (state.core.playlists[uri] !== undefined ? state.core.playlists[uri] : null),
|
||||
playlists: state.core.playlists,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditPlaylist)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditPlaylist);
|
||||
|
||||
@ -1,271 +1,271 @@
|
||||
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import Link from '../../components/Link'
|
||||
import ReactGA from 'react-ga'
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import ReactGA from 'react-ga';
|
||||
import Link from '../../components/Link';
|
||||
|
||||
import Modal from './Modal';
|
||||
import Icon from '../../components/Icon';
|
||||
|
||||
import * as coreActions from '../../services/core/actions'
|
||||
import * as uiActions from '../../services/ui/actions'
|
||||
import * as mopidyActions from '../../services/mopidy/actions'
|
||||
import * as spotifyActions from '../../services/spotify/actions'
|
||||
import * as pusherActions from '../../services/pusher/actions'
|
||||
import * as coreActions from '../../services/core/actions';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as mopidyActions from '../../services/mopidy/actions';
|
||||
import * as spotifyActions from '../../services/spotify/actions';
|
||||
import * as pusherActions from '../../services/pusher/actions';
|
||||
import * as helpers from '../../helpers';
|
||||
|
||||
class EditRadio extends React.Component{
|
||||
class EditRadio extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
enabled: false,
|
||||
seeds: [],
|
||||
uri: '',
|
||||
error_message: null,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {
|
||||
enabled: false,
|
||||
seeds: [],
|
||||
uri: '',
|
||||
error_message: null
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.uiActions.setWindowTitle('Edit radio');
|
||||
|
||||
componentDidMount(){
|
||||
this.props.uiActions.setWindowTitle("Edit radio");
|
||||
if (this.props.radio && this.props.radio.enabled) {
|
||||
this.loadRadio(this.props.radio);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.props.radio && this.props.radio.enabled){
|
||||
this.loadRadio(this.props.radio);
|
||||
}
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!this.props.radio && nextProps.radio) {
|
||||
this.loadRadio(nextProps.radio);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
if (!this.props.radio && nextProps.radio){
|
||||
this.loadRadio(nextProps.radio);
|
||||
}
|
||||
}
|
||||
loadRadio(radio) {
|
||||
const seeds = [...radio.seed_tracks, ...radio.seed_artists, ...radio.seed_genres];
|
||||
this.setState({ seeds, enabled: radio.enabled });
|
||||
this.props.spotifyActions.resolveRadioSeeds(radio);
|
||||
}
|
||||
|
||||
loadRadio(radio){
|
||||
var seeds = [...radio.seed_tracks, ...radio.seed_artists, ...radio.seed_genres];
|
||||
this.setState({seeds: seeds, enabled: radio.enabled});
|
||||
this.props.spotifyActions.resolveRadioSeeds(radio);
|
||||
}
|
||||
handleStart(e) {
|
||||
e.preventDefault();
|
||||
|
||||
handleStart(e){
|
||||
e.preventDefault();
|
||||
let valid_seeds = true;
|
||||
const seeds = this.mapSeeds();
|
||||
for (let i = 0; i < seeds.length; i++) {
|
||||
if (seeds[i].unresolved !== undefined) {
|
||||
valid_seeds = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let valid_seeds = true;
|
||||
let seeds = this.mapSeeds();
|
||||
for (let i = 0; i < seeds.length; i++){
|
||||
if (seeds[i].unresolved !== undefined){
|
||||
valid_seeds = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (valid_seeds) {
|
||||
this.props.pusherActions.startRadio(this.state.seeds);
|
||||
window.history.back();
|
||||
} else {
|
||||
this.setState({ error_message: 'Invalid seed URI(s)' });
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_seeds){
|
||||
this.props.pusherActions.startRadio(this.state.seeds);
|
||||
window.history.back();
|
||||
} else {
|
||||
this.setState({error_message: "Invalid seed URI(s)"});
|
||||
}
|
||||
}
|
||||
handleUpdate(e) {
|
||||
e.preventDefault();
|
||||
|
||||
handleUpdate(e){
|
||||
e.preventDefault();
|
||||
let valid_seeds = true;
|
||||
const seeds = this.mapSeeds();
|
||||
for (let i = 0; i < seeds.length; i++) {
|
||||
if (seeds[i].unresolved !== undefined) {
|
||||
valid_seeds = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var valid_seeds = true;
|
||||
var seeds = this.mapSeeds();
|
||||
for (var i = 0; i < seeds.length; i++){
|
||||
if (seeds[i].unresolved !== undefined){
|
||||
valid_seeds = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (valid_seeds) {
|
||||
this.props.pusherActions.updateRadio(this.state.seeds);
|
||||
this.props.uiActions.closeModal();
|
||||
} else {
|
||||
this.setState({ error_message: 'Invalid seed URI(s)' });
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_seeds){
|
||||
this.props.pusherActions.updateRadio(this.state.seeds);
|
||||
this.props.uiActions.closeModal();
|
||||
} else {
|
||||
this.setState({error_message: "Invalid seed URI(s)"});
|
||||
}
|
||||
}
|
||||
handleStop(e) {
|
||||
e.preventDefault();
|
||||
this.props.pusherActions.stopRadio();
|
||||
this.props.uiActions.closeModal();
|
||||
}
|
||||
|
||||
handleStop(e){
|
||||
e.preventDefault()
|
||||
this.props.pusherActions.stopRadio()
|
||||
this.props.uiActions.closeModal()
|
||||
}
|
||||
addSeed(e) {
|
||||
e.preventDefault();
|
||||
|
||||
addSeed(e){
|
||||
e.preventDefault();
|
||||
if (this.state.uri == '') {
|
||||
this.setState({ error_message: 'Cannot be empty' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.state.uri == ''){
|
||||
this.setState({error_message: 'Cannot be empty'});
|
||||
return;
|
||||
}
|
||||
this.setState({ error_message: null });
|
||||
|
||||
this.setState({error_message: null});
|
||||
const seeds = Object.assign([], this.state.seeds);
|
||||
let uris = this.state.uri.split(',');
|
||||
|
||||
var seeds = Object.assign([],this.state.seeds);
|
||||
var uris = this.state.uri.split(',');
|
||||
if (uris.length >= 5) {
|
||||
uris = uris.slice(0, 5);
|
||||
this.setState({ error_message: 'More than 5 seeds provided, ignoring rest' });
|
||||
}
|
||||
|
||||
if (uris.length >= 5) {
|
||||
uris = uris.slice(0, 5);
|
||||
this.setState({error_message: 'More than 5 seeds provided, ignoring rest'});
|
||||
}
|
||||
for (let i = 0; i < uris.length; i++) {
|
||||
if (helpers.uriSource(uris[i]) !== 'spotify') {
|
||||
this.setState({ error_message: 'Non-Spotify URIs not supported' });
|
||||
return;
|
||||
} if (seeds.indexOf(uris[i]) > -1) {
|
||||
this.setState({ error_message: 'URI already added' });
|
||||
} else {
|
||||
seeds.push(uris[i]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < uris.length; i++){
|
||||
if (helpers.uriSource(uris[i]) !== 'spotify'){
|
||||
this.setState({error_message: 'Non-Spotify URIs not supported'});
|
||||
return;
|
||||
} else if (seeds.indexOf(uris[i]) > -1){
|
||||
this.setState({error_message: 'URI already added'});
|
||||
} else {
|
||||
seeds.push(uris[i]);
|
||||
}
|
||||
// Resolve
|
||||
switch (helpers.uriType(uris[i])) {
|
||||
case 'track':
|
||||
this.props.spotifyActions.getTrack(uris[i]);
|
||||
break;
|
||||
|
||||
// Resolve
|
||||
switch (helpers.uriType(uris[i])){
|
||||
case 'track':
|
||||
this.props.spotifyActions.getTrack(uris[i]);
|
||||
break;
|
||||
case 'artist':
|
||||
this.props.spotifyActions.getArtist(uris[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case 'artist':
|
||||
this.props.spotifyActions.getArtist(uris[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// commit to state
|
||||
this.setState({
|
||||
seeds,
|
||||
uri: '',
|
||||
});
|
||||
}
|
||||
|
||||
// commit to state
|
||||
this.setState({
|
||||
seeds: seeds,
|
||||
uri: ''
|
||||
})
|
||||
}
|
||||
removeSeed(uri) {
|
||||
const seeds = [];
|
||||
for (let i = 0; i < this.state.seeds.length; i++) {
|
||||
if (this.state.seeds[i] != uri) {
|
||||
seeds.push(this.state.seeds[i]);
|
||||
}
|
||||
}
|
||||
this.setState({ seeds });
|
||||
}
|
||||
|
||||
removeSeed(uri){
|
||||
var seeds = []
|
||||
for (var i = 0; i < this.state.seeds.length; i++){
|
||||
if (this.state.seeds[i] != uri){
|
||||
seeds.push(this.state.seeds[i])
|
||||
}
|
||||
}
|
||||
this.setState({seeds: seeds});
|
||||
}
|
||||
mapSeeds() {
|
||||
const seeds = [];
|
||||
|
||||
mapSeeds(){
|
||||
var seeds = []
|
||||
if (this.state.seeds) {
|
||||
for (let i = 0; i < this.state.seeds.length && i < 5; i++) {
|
||||
const uri = this.state.seeds[i];
|
||||
if (uri) {
|
||||
if (helpers.uriType(uri) == 'artist') {
|
||||
if (this.props.artists && this.props.artists.hasOwnProperty(uri)) {
|
||||
seeds.push(this.props.artists[uri]);
|
||||
} else {
|
||||
seeds.push({
|
||||
unresolved: true,
|
||||
uri,
|
||||
});
|
||||
}
|
||||
} else if (helpers.uriType(uri) == 'track') {
|
||||
if (this.props.tracks && this.props.tracks.hasOwnProperty(uri)) {
|
||||
seeds.push(this.props.tracks[uri]);
|
||||
} else {
|
||||
seeds.push({
|
||||
unresolved: true,
|
||||
uri,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state.seeds){
|
||||
for (var i = 0; i < this.state.seeds.length && i < 5; i++){
|
||||
var uri = this.state.seeds[i]
|
||||
if (uri){
|
||||
if (helpers.uriType(uri) == 'artist'){
|
||||
if (this.props.artists && this.props.artists.hasOwnProperty(uri)){
|
||||
seeds.push(this.props.artists[uri]);
|
||||
} else {
|
||||
seeds.push({
|
||||
unresolved: true,
|
||||
uri: uri
|
||||
})
|
||||
return seeds;
|
||||
}
|
||||
|
||||
renderSeeds() {
|
||||
const seeds = this.mapSeeds();
|
||||
|
||||
if (seeds.length > 0) {
|
||||
return (
|
||||
<div>
|
||||
<div className="list">
|
||||
{
|
||||
seeds.map((seed, index) => (
|
||||
<div className="list__item" key={seed.uri}>
|
||||
{seed.unresolved ? <span className="mid_grey-text">{seed.uri}</span> : <span>{seed.name}</span> }
|
||||
{!seed.unresolved ? (
|
||||
<span className="mid_grey-text">
|
||||
(
|
||||
{helpers.uriType(seed.uri)}
|
||||
)
|
||||
</span>
|
||||
) : null}
|
||||
<span className="button discrete remove-uri no-hover" onClick={(e) => this.removeSeed(seed.uri)}>
|
||||
<Icon name="delete" />
|
||||
Remove
|
||||
</span>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
} else if (helpers.uriType(uri) == 'track'){
|
||||
if (this.props.tracks && this.props.tracks.hasOwnProperty(uri)){
|
||||
seeds.push(this.props.tracks[uri]);
|
||||
} else {
|
||||
seeds.push({
|
||||
unresolved: true,
|
||||
uri: uri
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="no-results">No seeds</div>
|
||||
);
|
||||
}
|
||||
|
||||
return seeds;
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Modal className="modal--edit-radio">
|
||||
<h1>Radio</h1>
|
||||
<h2 className="mid_grey-text">Add and remove seeds to shape the sound of your radio. Radio uses Spotify's recommendations engine to suggest tracks similar to your seeds.</h2>
|
||||
|
||||
renderSeeds(){
|
||||
var seeds = this.mapSeeds();
|
||||
<form onSubmit={(e) => { (this.state.enabled ? this.handleUpdate(e) : this.handleStart(e)); }}>
|
||||
|
||||
if (seeds.length > 0){
|
||||
return (
|
||||
<div>
|
||||
<div className="list">
|
||||
{
|
||||
seeds.map((seed,index) => {
|
||||
return (
|
||||
<div className="list__item" key={seed.uri}>
|
||||
{seed.unresolved ? <span className="mid_grey-text">{seed.uri}</span> : <span>{seed.name}</span> }
|
||||
{!seed.unresolved ? <span className="mid_grey-text"> ({helpers.uriType(seed.uri)})</span> : null}
|
||||
<span className="button discrete remove-uri no-hover" onClick={e => this.removeSeed(seed.uri)}>
|
||||
<Icon name="delete" />Remove
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div className="no-results">No seeds</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
{this.renderSeeds()}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<Modal className="modal--edit-radio">
|
||||
<h1>Radio</h1>
|
||||
<h2 className="mid_grey-text">Add and remove seeds to shape the sound of your radio. Radio uses Spotify's recommendations engine to suggest tracks similar to your seeds.</h2>
|
||||
<div className="field text">
|
||||
<div className="name">URI(s)</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ uri: e.target.value, error_message: null })}
|
||||
value={this.state.uri}
|
||||
/>
|
||||
<span className="button discrete add-uri no-hover" onClick={(e) => this.addSeed(e)}>
|
||||
<Icon name="add" />
|
||||
Add
|
||||
</span>
|
||||
{this.state.error_message ? <span className="description error">{this.state.error_message}</span> : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form onSubmit={e => {(this.state.enabled ? this.handleUpdate(e) : this.handleStart(e))}}>
|
||||
<div className="actions centered-text">
|
||||
{this.state.enabled ? <span className="button button--destructive button--large" onClick={(e) => this.handleStop(e)}>Stop</span> : null}
|
||||
|
||||
{this.renderSeeds()}
|
||||
|
||||
<div className="field text">
|
||||
<div className="name">URI(s)</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={e => this.setState({uri: e.target.value, error_message: null})}
|
||||
value={this.state.uri}
|
||||
/>
|
||||
<span className="button discrete add-uri no-hover" onClick={e => this.addSeed(e)}>
|
||||
<Icon name="add" />Add
|
||||
</span>
|
||||
{this.state.error_message ? <span className="description error">{this.state.error_message}</span> : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="actions centered-text">
|
||||
{this.state.enabled ? <span className="button button--destructive button--large" onClick={e => this.handleStop(e)}>Stop</span> : null}
|
||||
|
||||
{this.state.enabled ? <button className="button button--primary button--large" onClick={e => this.handleUpdate(e)}>Save</button> : <button className="button button--primary button--large" onClick={e => this.handleStart(e)}>Start</button>}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
{this.state.enabled ? <button className="button button--primary button--large" onClick={(e) => this.handleUpdate(e)}>Save</button> : <button className="button button--primary button--large" onClick={(e) => this.handleStart(e)}>Start</button>}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
radio: state.core.radio,
|
||||
artists: state.core.artists,
|
||||
tracks: state.core.tracks
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
radio: state.core.radio,
|
||||
artists: state.core.artists,
|
||||
tracks: state.core.tracks,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
pusherActions: bindActionCreators(pusherActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
pusherActions: bindActionCreators(pusherActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditRadio)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditRadio);
|
||||
|
||||
@ -9,33 +9,28 @@ import Thumbnail from '../../components/Thumbnail';
|
||||
import * as helpers from '../../helpers';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
|
||||
class ImageZoom extends React.Component{
|
||||
class ImageZoom extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.uiActions.setWindowTitle('Zoomed image');
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.props.uiActions.setWindowTitle("Zoomed image");
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<Modal className="modal--image-zoom">
|
||||
<img src={this.props.location.search.replace("?url=","")} />
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Modal className="modal--image-zoom">
|
||||
<img src={this.props.location.search.replace('?url=', '')} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {}
|
||||
}
|
||||
const mapStateToProps = (state) => ({});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
uiActions: bindActionCreators(uiActions, dispatch)
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ImageZoom)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ImageZoom);
|
||||
|
||||
@ -11,145 +11,151 @@ import * as pusherActions from '../../services/pusher/actions';
|
||||
import * as mopidyActions from '../../services/mopidy/actions';
|
||||
import * as helpers from '../../helpers';
|
||||
|
||||
class InitialSetup extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
class InitialSetup extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
username: this.props.username,
|
||||
allow_reporting: this.props.allow_reporting,
|
||||
host: this.props.host,
|
||||
port: this.props.port
|
||||
}
|
||||
}
|
||||
this.state = {
|
||||
username: this.props.username,
|
||||
allow_reporting: this.props.allow_reporting,
|
||||
host: this.props.host,
|
||||
port: this.props.port,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.props.uiActions.setWindowTitle("Welcome to Iris");
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.uiActions.setWindowTitle('Welcome to Iris');
|
||||
}
|
||||
|
||||
handleSubmit(e){
|
||||
e.preventDefault();
|
||||
var self = this;
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const self = this;
|
||||
|
||||
// Only if we've changed the username do we set it
|
||||
if (this.props.username !== this.state.username){
|
||||
this.props.pusherActions.setUsername(this.state.username);
|
||||
}
|
||||
// Only if we've changed the username do we set it
|
||||
if (this.props.username !== this.state.username) {
|
||||
this.props.pusherActions.setUsername(this.state.username);
|
||||
}
|
||||
|
||||
this.props.uiActions.set({
|
||||
initial_setup_complete: true,
|
||||
allow_reporting: this.state.allow_reporting
|
||||
});
|
||||
this.props.uiActions.set({
|
||||
initial_setup_complete: true,
|
||||
allow_reporting: this.state.allow_reporting,
|
||||
});
|
||||
|
||||
this.props.mopidyActions.set({
|
||||
host: this.state.host,
|
||||
port: this.state.port
|
||||
});
|
||||
this.props.mopidyActions.set({
|
||||
host: this.state.host,
|
||||
port: this.state.port,
|
||||
});
|
||||
|
||||
this.setState({saving: true});
|
||||
this.setState({ saving: true });
|
||||
|
||||
// Wait a jiffy to allow changes to apply to store
|
||||
setTimeout(() => {
|
||||
// Wait a jiffy to allow changes to apply to store
|
||||
setTimeout(() => {
|
||||
// We've changed a connection setting, so need to reload
|
||||
if (self.state.host !== self.props.host || self.state.port !== self.props.port) {
|
||||
window.location = '/';
|
||||
|
||||
// We've changed a connection setting, so need to reload
|
||||
if (self.state.host !== self.props.host || self.state.port !== self.props.port){
|
||||
window.location = '/';
|
||||
// Safe to just close modal
|
||||
} else {
|
||||
self.props.history.push('/');
|
||||
}
|
||||
},
|
||||
200);
|
||||
|
||||
// Safe to just close modal
|
||||
} else {
|
||||
self.props.history.push('/');
|
||||
}
|
||||
},
|
||||
200
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Modal className="modal--initial-setup" noclose>
|
||||
<h1>Get started</h1>
|
||||
<form onSubmit={(e) => this.handleSubmit(e)}>
|
||||
|
||||
render(){
|
||||
return (
|
||||
<Modal className="modal--initial-setup" noclose>
|
||||
<h1>Get started</h1>
|
||||
<form onSubmit={(e) => this.handleSubmit(e)}>
|
||||
|
||||
<div className="field text">
|
||||
<div className="name">
|
||||
<div className="field text">
|
||||
<div className="name">
|
||||
Username
|
||||
</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={e => this.setState({username: e.target.value.replace(/\W/g, '')})}
|
||||
value={this.state.username } />
|
||||
<div className="description">
|
||||
</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ username: e.target.value.replace(/\W/g, '') })}
|
||||
value={this.state.username}
|
||||
/>
|
||||
<div className="description">
|
||||
A non-unique string used to identify this client (no special characters)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<div className="name">Host</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={ e => this.setState({host: e.target.value})}
|
||||
value={ this.state.host } />
|
||||
</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<div className="name">Port</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={ e => this.setState({port: e.target.value})}
|
||||
value={ this.state.port } />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{helpers.isHosted() ? null : <div className="field checkbox">
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="allow_reporting"
|
||||
checked={ this.state.allow_reporting }
|
||||
onChange={ e => this.setState({ allow_reporting: !this.state.allow_reporting })} />
|
||||
<span className="label">
|
||||
<div className="field">
|
||||
<div className="name">Host</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ host: e.target.value })}
|
||||
value={this.state.host}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<div className="name">Port</div>
|
||||
<div className="input">
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ port: e.target.value })}
|
||||
value={this.state.port}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{helpers.isHosted() ? null : (
|
||||
<div className="field checkbox">
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="allow_reporting"
|
||||
checked={this.state.allow_reporting}
|
||||
onChange={(e) => this.setState({ allow_reporting: !this.state.allow_reporting })}
|
||||
/>
|
||||
<span className="label">
|
||||
Allow reporting of anonymous usage statistics
|
||||
</span>
|
||||
</label>
|
||||
<p className="description">This anonymous usage data is important in identifying errors and potential features that make Iris better for everyone. Want to know more? Read the <a href="https://github.com/jaedb/Iris/wiki/Terms-of-use#privacy-policy" target="_blank">privacy policy</a>{!this.state.allow_reporting ? <span className="red-text"> Are you sure you don't want to support this?</span> : null}. </p>
|
||||
</div>
|
||||
</div>}
|
||||
</span>
|
||||
</label>
|
||||
<p className="description">
|
||||
This anonymous usage data is important in identifying errors and potential features that make Iris better for everyone. Want to know more? Read the
|
||||
<a href="https://github.com/jaedb/Iris/wiki/Terms-of-use#privacy-policy" target="_blank">privacy policy</a>
|
||||
{!this.state.allow_reporting ? <span className="red-text"> Are you sure you don't want to support this?</span> : null}
|
||||
.
|
||||
{' '}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="actions centered-text">
|
||||
<button className={"button button--primary button--large"+(this.state.saving ? " button--working" : "")} onClick={e => this.handleSubmit(e)}>
|
||||
{this.state.saving ? "Saving" : "Save"}
|
||||
</button>
|
||||
</div>
|
||||
<div className="actions centered-text">
|
||||
<button className={`button button--primary button--large${this.state.saving ? ' button--working' : ''}`} onClick={(e) => this.handleSubmit(e)}>
|
||||
{this.state.saving ? 'Saving' : 'Save'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
allow_reporting: state.ui.allow_reporting,
|
||||
username: (state.pusher && state.pusher.username ? state.pusher.username : null),
|
||||
host: state.mopidy.host,
|
||||
port: state.mopidy.port
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
allow_reporting: state.ui.allow_reporting,
|
||||
username: (state.pusher && state.pusher.username ? state.pusher.username : null),
|
||||
host: state.mopidy.host,
|
||||
port: state.mopidy.port,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
pusherActions: bindActionCreators(pusherActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch)
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
pusherActions: bindActionCreators(pusherActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(InitialSetup)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(InitialSetup);
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import Link from '../../components/Link'
|
||||
import { createStore, bindActionCreators } from 'redux';
|
||||
import Link from '../../components/Link';
|
||||
|
||||
import Modal from './Modal';
|
||||
import Thumbnail from '../../components/Thumbnail';
|
||||
@ -15,89 +15,84 @@ import * as helpers from '../../helpers';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as mopidyActions from '../../services/mopidy/actions';
|
||||
|
||||
class KioskMode extends React.Component{
|
||||
class KioskMode extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
}
|
||||
componentDidMount() {
|
||||
this.setWindowTitle();
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.setWindowTitle();
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!this.props.current_track && nextProps.current_track) {
|
||||
this.setWindowTitle(nextProps.current_track);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
if (!this.props.current_track && nextProps.current_track){
|
||||
this.setWindowTitle(nextProps.current_track);
|
||||
}
|
||||
}
|
||||
setWindowTitle(current_track = this.props.current_track) {
|
||||
if (current_track) {
|
||||
let artists = '';
|
||||
for (let i = 0; i < current_track.artists.length; i++) {
|
||||
if (artists != '') {
|
||||
artists += ', ';
|
||||
}
|
||||
artists += current_track.artists[i].name;
|
||||
}
|
||||
this.props.uiActions.setWindowTitle(`${current_track.name} by ${artists} (now playing)`);
|
||||
} else {
|
||||
this.props.uiActions.setWindowTitle('Now playing');
|
||||
}
|
||||
}
|
||||
|
||||
setWindowTitle(current_track = this.props.current_track){
|
||||
if (current_track){
|
||||
var artists = "";
|
||||
for (var i = 0; i < current_track.artists.length; i++){
|
||||
if (artists != ""){
|
||||
artists += ", ";
|
||||
}
|
||||
artists += current_track.artists[i].name;
|
||||
}
|
||||
this.props.uiActions.setWindowTitle(current_track.name+" by "+artists+" (now playing)");
|
||||
} else{
|
||||
this.props.uiActions.setWindowTitle("Now playing");
|
||||
}
|
||||
}
|
||||
togglePlay(e) {
|
||||
if (this.props.play_state == 'playing') {
|
||||
this.props.mopidyActions.pause();
|
||||
} else {
|
||||
this.props.mopidyActions.play();
|
||||
}
|
||||
}
|
||||
|
||||
togglePlay(e){
|
||||
if (this.props.play_state == 'playing'){
|
||||
this.props.mopidyActions.pause();
|
||||
} else {
|
||||
this.props.mopidyActions.play();
|
||||
}
|
||||
}
|
||||
render() {
|
||||
if (this.props.current_track && this.props.current_track.images) {
|
||||
var { images } = this.props.current_track;
|
||||
} else {
|
||||
var images = [];
|
||||
}
|
||||
|
||||
render(){
|
||||
if (this.props.current_track && this.props.current_track.images){
|
||||
var images = this.props.current_track.images
|
||||
} else {
|
||||
var images = []
|
||||
}
|
||||
return (
|
||||
<Modal className="modal--kiosk-mode">
|
||||
|
||||
return (
|
||||
<Modal className="modal--kiosk-mode">
|
||||
|
||||
<Thumbnail className="background" images={images} />
|
||||
<Thumbnail className="background" images={images} />
|
||||
|
||||
<div className="artwork" onClick={e => this.togglePlay(e)}>
|
||||
<Thumbnail images={images} />
|
||||
{this.props.play_state == 'playing' ? <Icon name="pause_circle_filled" /> : <Icon name="play_circle_filled" />}
|
||||
</div>
|
||||
<div className="artwork" onClick={(e) => this.togglePlay(e)}>
|
||||
<Thumbnail images={images} />
|
||||
{this.props.play_state == 'playing' ? <Icon name="pause_circle_filled" /> : <Icon name="play_circle_filled" />}
|
||||
</div>
|
||||
|
||||
<div className="player">
|
||||
<div className="current-track">
|
||||
<div className="title">{ this.props.current_track ? this.props.current_track.name : <span>-</span> }</div>
|
||||
{ this.props.current_track ? <ArtistSentence nolinks artists={ this.props.current_track.artists } /> : <ArtistSentence /> }
|
||||
</div>
|
||||
<div className="player">
|
||||
<div className="current-track">
|
||||
<div className="title">{ this.props.current_track ? this.props.current_track.name : <span>-</span> }</div>
|
||||
{ this.props.current_track ? <ArtistSentence nolinks artists={this.props.current_track.artists} /> : <ArtistSentence /> }
|
||||
</div>
|
||||
|
||||
<div className="progress-wrapper">
|
||||
<ProgressSlider />
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
<div className="progress-wrapper">
|
||||
<ProgressSlider />
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
play_state: state.mopidy.play_state,
|
||||
current_track: (state.core.current_track && state.core.tracks[state.core.current_track.uri] !== undefined ? state.core.tracks[state.core.current_track.uri] : null),
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state) => ({
|
||||
play_state: state.mopidy.play_state,
|
||||
current_track: (state.core.current_track && state.core.tracks[state.core.current_track.uri] !== undefined ? state.core.tracks[state.core.current_track.uri] : null),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch)
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(KioskMode)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(KioskMode);
|
||||
|
||||
@ -3,55 +3,51 @@ import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
|
||||
import * as helpers from '../../helpers'
|
||||
import Icon from '../../components/Icon'
|
||||
import * as helpers from '../../helpers';
|
||||
import Icon from '../../components/Icon';
|
||||
|
||||
class Modal extends React.Component{
|
||||
class Modal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
componentWillMount() {
|
||||
$('body').addClass('modal-open');
|
||||
}
|
||||
|
||||
componentWillMount(){
|
||||
$('body').addClass('modal-open');
|
||||
}
|
||||
componentWillUnmount() {
|
||||
$('body').removeClass('modal-open');
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
$('body').removeClass('modal-open');
|
||||
}
|
||||
render() {
|
||||
let className = 'modal';
|
||||
if (this.props.className) {
|
||||
className += ` ${this.props.className}`;
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div className={className}>
|
||||
|
||||
var className = "modal";
|
||||
if (this.props.className){
|
||||
className += " "+this.props.className;
|
||||
}
|
||||
<div className="controls">
|
||||
{this.props.noclose ? null : (
|
||||
<div className="control close" onClick={(e) => window.history.back()}>
|
||||
<Icon name="close" className="white" />
|
||||
</div>
|
||||
) }
|
||||
</div>
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
|
||||
<div className="controls">
|
||||
{this.props.noclose ? null : <div className="control close" onClick={e => window.history.back()}>
|
||||
<Icon name="close" className="white" />
|
||||
</div> }
|
||||
</div>
|
||||
|
||||
<div className="content">
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
<div className="content">
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
shortkeys_enabled: state.ui.shortkeys_enabled
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
shortkeys_enabled: state.ui.shortkeys_enabled,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Modal)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Modal);
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import Link from '../../components/Link'
|
||||
import { createStore, bindActionCreators } from 'redux'
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createStore, bindActionCreators } from 'redux';
|
||||
import Link from '../../components/Link';
|
||||
|
||||
import Modal from './Modal';
|
||||
import Icon from '../../components/Icon';
|
||||
@ -11,208 +11,221 @@ import * as uiActions from '../../services/ui/actions';
|
||||
import * as pusherActions from '../../services/pusher/actions';
|
||||
import * as helpers from '../../helpers';
|
||||
|
||||
class ShareConfiguration extends React.Component {
|
||||
class ShareConfiguration extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
recipients: [],
|
||||
spotify: false,
|
||||
lastfm: false,
|
||||
genius: false,
|
||||
ui: false,
|
||||
};
|
||||
}
|
||||
|
||||
this.state = {
|
||||
recipients: [],
|
||||
spotify: false,
|
||||
lastfm: false,
|
||||
genius: false,
|
||||
ui: false
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.uiActions.setWindowTitle('Share configuration');
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.props.uiActions.setWindowTitle("Share configuration");
|
||||
}
|
||||
toggleRecipient(id) {
|
||||
const { recipients } = this.state;
|
||||
if (recipients.includes(id)) {
|
||||
const index = recipients.indexOf(id);
|
||||
recipients.splice(index, 1);
|
||||
} else {
|
||||
recipients.push(id);
|
||||
}
|
||||
this.setState({ recipients });
|
||||
}
|
||||
|
||||
toggleRecipient(id){
|
||||
var recipients = this.state.recipients;
|
||||
if (recipients.includes(id)){
|
||||
var index = recipients.indexOf(id);
|
||||
recipients.splice(index,1);
|
||||
} else {
|
||||
recipients.push(id);
|
||||
}
|
||||
this.setState({recipients: recipients});
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
handleSubmit(e){
|
||||
e.preventDefault();
|
||||
const configuration = {};
|
||||
if (this.state.spotify) {
|
||||
configuration.spotify = {
|
||||
authorization: this.props.spotify_authorization,
|
||||
me: this.props.spotify_me,
|
||||
};
|
||||
}
|
||||
if (this.state.genius) {
|
||||
configuration.genius = {
|
||||
authorization: this.props.genius_authorization,
|
||||
me: this.props.genius_me,
|
||||
};
|
||||
}
|
||||
if (this.state.lastfm) {
|
||||
configuration.lastfm = {
|
||||
authorization: this.props.lastfm_authorization,
|
||||
me: this.props.lastfm_me,
|
||||
};
|
||||
}
|
||||
if (this.state.ui) {
|
||||
configuration.ui = this.props.ui;
|
||||
}
|
||||
|
||||
var configuration = {};
|
||||
if (this.state.spotify){
|
||||
configuration.spotify = {
|
||||
authorization: this.props.spotify_authorization,
|
||||
me: this.props.spotify_me
|
||||
}
|
||||
}
|
||||
if (this.state.genius){
|
||||
configuration.genius = {
|
||||
authorization: this.props.genius_authorization,
|
||||
me: this.props.genius_me
|
||||
}
|
||||
}
|
||||
if (this.state.lastfm){
|
||||
configuration.lastfm = {
|
||||
authorization: this.props.lastfm_authorization,
|
||||
me: this.props.lastfm_me
|
||||
}
|
||||
}
|
||||
if (this.state.ui){
|
||||
configuration.ui = this.props.ui;
|
||||
}
|
||||
for (const recipient of this.state.recipients) {
|
||||
this.props.pusherActions.deliverMessage(
|
||||
recipient,
|
||||
'share_configuration_received',
|
||||
configuration,
|
||||
);
|
||||
}
|
||||
|
||||
for (var recipient of this.state.recipients){
|
||||
this.props.pusherActions.deliverMessage(
|
||||
recipient,
|
||||
'share_configuration_received',
|
||||
configuration
|
||||
);
|
||||
}
|
||||
window.history.back();
|
||||
}
|
||||
|
||||
window.history.back();
|
||||
return;
|
||||
}
|
||||
render() {
|
||||
const connections = [];
|
||||
for (const connection_id in this.props.connections) {
|
||||
if (this.props.connections.hasOwnProperty(connection_id) && connection_id != this.props.connection_id) {
|
||||
connections.push(this.props.connections[connection_id]);
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
var connections = []
|
||||
for (var connection_id in this.props.connections){
|
||||
if (this.props.connections.hasOwnProperty(connection_id) && connection_id != this.props.connection_id){
|
||||
connections.push(this.props.connections[connection_id])
|
||||
}
|
||||
}
|
||||
|
||||
if (connections.length > 0){
|
||||
var recipients = (
|
||||
<div className="input">
|
||||
{
|
||||
connections.map((connection, index) => {
|
||||
return (
|
||||
<label key={connection.connection_id}>
|
||||
<input
|
||||
type="checkbox"
|
||||
name={"connection_"+connection.connection_id}
|
||||
checked={this.state.recipients.includes(connection.connection_id)}
|
||||
onChange={e => this.toggleRecipient(connection.connection_id)}
|
||||
/>
|
||||
<span className="label">
|
||||
<div className="title">{ connection.username }</div>
|
||||
<div className="description mid_grey-text">
|
||||
({ connection.ip })
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
);
|
||||
})
|
||||
if (connections.length > 0) {
|
||||
var recipients = (
|
||||
<div className="input">
|
||||
{
|
||||
connections.map((connection, index) => (
|
||||
<label key={connection.connection_id}>
|
||||
<input
|
||||
type="checkbox"
|
||||
name={`connection_${connection.connection_id}`}
|
||||
checked={this.state.recipients.includes(connection.connection_id)}
|
||||
onChange={(e) => this.toggleRecipient(connection.connection_id)}
|
||||
/>
|
||||
<span className="label">
|
||||
<div className="title">{ connection.username }</div>
|
||||
<div className="description mid_grey-text">
|
||||
(
|
||||
{ connection.ip }
|
||||
)
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
var recipients = (
|
||||
<div className="input text">
|
||||
<span className="mid_grey-text">
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
var recipients = (
|
||||
<div className="input text">
|
||||
<span className="mid_grey-text">
|
||||
No peer connections
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal className="modal--share-configuration">
|
||||
|
||||
<h1>Share configuration</h1>
|
||||
<h2>Push your authorizations and interface settings to another, connected user</h2>
|
||||
return (
|
||||
<Modal className="modal--share-configuration">
|
||||
|
||||
<form onSubmit={e => this.handleSubmit(e)}>
|
||||
<div className="field checkbox white">
|
||||
<div className="name">Recipients</div>
|
||||
{recipients}
|
||||
</div>
|
||||
<h1>Share configuration</h1>
|
||||
<h2>Push your authorizations and interface settings to another, connected user</h2>
|
||||
|
||||
<div className="field checkbox checkbox--block">
|
||||
<div className="name">Configurations</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="interface"
|
||||
checked={ this.state.ui }
|
||||
onChange={ e => this.setState({ ui: !this.state.ui })} />
|
||||
<span className="label">
|
||||
<span className="title">UI customisation (theme, sorting, filters)</span>
|
||||
</span>
|
||||
</label>
|
||||
<form onSubmit={(e) => this.handleSubmit(e)}>
|
||||
<div className="field checkbox white">
|
||||
<div className="name">Recipients</div>
|
||||
{recipients}
|
||||
</div>
|
||||
|
||||
{this.props.spotify_me && this.props.spotify_authorization ? <label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="spotify"
|
||||
checked={this.state.spotify}
|
||||
onChange={ e => this.setState({ spotify: !this.state.spotify })} />
|
||||
<span className="label">
|
||||
<div className="title">Spotify authorization</div>
|
||||
<div className="description mid_grey-text">Logged in as {this.props.spotify_me.name}</div>
|
||||
</span>
|
||||
</label> : null}
|
||||
<div className="field checkbox checkbox--block">
|
||||
<div className="name">Configurations</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="interface"
|
||||
checked={this.state.ui}
|
||||
onChange={(e) => this.setState({ ui: !this.state.ui })}
|
||||
/>
|
||||
<span className="label">
|
||||
<span className="title">UI customisation (theme, sorting, filters)</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
{this.props.lastfm_me && this.props.lastfm_authorization ? <label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="lastfm_authorization"
|
||||
checked={this.state.lastfm}
|
||||
onChange={ e => this.setState({ lastfm: !this.state.lastfm })} />
|
||||
<span className="label">
|
||||
<div className="title">LastFM authorization</div>
|
||||
<div className="description mid_grey-text">Logged in as {this.props.lastfm_me.name}</div>
|
||||
</span>
|
||||
</label> : null}
|
||||
{this.props.spotify_me && this.props.spotify_authorization ? (
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="spotify"
|
||||
checked={this.state.spotify}
|
||||
onChange={(e) => this.setState({ spotify: !this.state.spotify })}
|
||||
/>
|
||||
<span className="label">
|
||||
<div className="title">Spotify authorization</div>
|
||||
<div className="description mid_grey-text">
|
||||
Logged in as
|
||||
{this.props.spotify_me.name}
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
) : null}
|
||||
|
||||
{this.props.genius_me && this.props.genius_authorization ? <label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="genius_authorization"
|
||||
checked={this.state.genius}
|
||||
onChange={ e => this.setState({ genius: !this.state.genius })} />
|
||||
<span className="label">
|
||||
<div className="title">Genius authorization</div>
|
||||
<div className="description mid_grey-text">Logged in as {this.props.genius_me.name}</div>
|
||||
</span>
|
||||
</label> : null}
|
||||
</div>
|
||||
</div>
|
||||
{this.props.lastfm_me && this.props.lastfm_authorization ? (
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="lastfm_authorization"
|
||||
checked={this.state.lastfm}
|
||||
onChange={(e) => this.setState({ lastfm: !this.state.lastfm })}
|
||||
/>
|
||||
<span className="label">
|
||||
<div className="title">LastFM authorization</div>
|
||||
<div className="description mid_grey-text">
|
||||
Logged in as
|
||||
{this.props.lastfm_me.name}
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
) : null}
|
||||
|
||||
<div className="actions centered-text">
|
||||
{this.state.recipients.length > 0 ? <button className="button button--primary button--large" onClick={e => this.handleSubmit(e)}>Send</button> : <button className="button button--primary button--large" disabled="disabled" onClick={e => this.handleSubmit(e)}>Send</button>}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
{this.props.genius_me && this.props.genius_authorization ? (
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="genius_authorization"
|
||||
checked={this.state.genius}
|
||||
onChange={(e) => this.setState({ genius: !this.state.genius })}
|
||||
/>
|
||||
<span className="label">
|
||||
<div className="title">Genius authorization</div>
|
||||
<div className="description mid_grey-text">
|
||||
Logged in as
|
||||
{this.props.genius_me.name}
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="actions centered-text">
|
||||
{this.state.recipients.length > 0 ? <button className="button button--primary button--large" onClick={(e) => this.handleSubmit(e)}>Send</button> : <button className="button button--primary button--large" disabled="disabled" onClick={(e) => this.handleSubmit(e)}>Send</button>}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
spotify_authorization: state.spotify.authorization,
|
||||
spotify_me: state.spotify.me,
|
||||
genius_authorization: state.genius.authorization,
|
||||
genius_me: state.genius.me,
|
||||
lastfm_authorization: state.lastfm.authorization,
|
||||
lastfm_me: state.lastfm.me,
|
||||
ui: state.ui,
|
||||
connection_id: state.pusher.connection_id,
|
||||
connections: state.pusher.connections
|
||||
}
|
||||
}
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
spotify_authorization: state.spotify.authorization,
|
||||
spotify_me: state.spotify.me,
|
||||
genius_authorization: state.genius.authorization,
|
||||
genius_me: state.genius.me,
|
||||
lastfm_authorization: state.lastfm.authorization,
|
||||
lastfm_me: state.lastfm.me,
|
||||
ui: state.ui,
|
||||
connection_id: state.pusher.connection_id,
|
||||
connections: state.pusher.connections,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
pusherActions: bindActionCreators(pusherActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch)
|
||||
}
|
||||
}
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
pusherActions: bindActionCreators(pusherActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ShareConfiguration)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ShareConfiguration);
|
||||
|
||||
Reference in New Issue
Block a user