2017-01-30 16:59:37 +13:00
|
|
|
|
2019-09-05 15:36:11 +12:00
|
|
|
import React from 'react';
|
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
|
import { bindActionCreators } from 'redux';
|
2018-07-09 19:09:12 +12:00
|
|
|
import Modal from './Modal';
|
|
|
|
|
import Icon from '../../components/Icon';
|
2019-09-05 15:36:11 +12:00
|
|
|
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';
|
2020-03-03 16:39:37 +13:00
|
|
|
import {
|
|
|
|
|
uriSource,
|
|
|
|
|
uriType,
|
|
|
|
|
} from '../../util/helpers';
|
2020-07-23 21:07:08 +12:00
|
|
|
import { i18n, I18n } from '../../locale';
|
2020-08-03 07:08:16 +12:00
|
|
|
import TextField from '../../components/Fields/TextField';
|
2020-08-16 20:00:10 +12:00
|
|
|
import Button from '../../components/Button';
|
2020-08-03 07:08:16 +12:00
|
|
|
|
|
|
|
|
const SeedListItem = ({ seed, remove }) => (
|
|
|
|
|
<div className="list__item list__item--no-interaction" key={seed.uri}>
|
|
|
|
|
{seed.unresolved ? (
|
|
|
|
|
<span className="mid_grey-text">{seed.uri}</span>
|
|
|
|
|
) : (
|
|
|
|
|
<span>{seed.name}</span>
|
|
|
|
|
)}
|
|
|
|
|
{!seed.unresolved && (
|
|
|
|
|
<span className="mid_grey-text">
|
|
|
|
|
{` (${uriType(seed.uri)})`}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
2020-08-16 20:00:10 +12:00
|
|
|
<Button
|
|
|
|
|
type="destructive"
|
|
|
|
|
size="tiny"
|
|
|
|
|
className="pull-right"
|
|
|
|
|
discrete
|
2020-08-03 07:08:16 +12:00
|
|
|
onClick={() => remove(seed.uri)}
|
2020-08-16 20:00:10 +12:00
|
|
|
tracking={{ category: 'Directory', action: 'Play' }}
|
2020-08-03 07:08:16 +12:00
|
|
|
>
|
|
|
|
|
<Icon name="delete" />
|
|
|
|
|
<I18n path="actions.remove" />
|
2020-08-16 20:00:10 +12:00
|
|
|
</Button>
|
2020-08-03 07:08:16 +12:00
|
|
|
</div>
|
|
|
|
|
);
|
2017-01-30 16:59:37 +13:00
|
|
|
|
2019-10-03 09:21:38 +13:00
|
|
|
class EditRadio extends React.Component {
|
2019-09-05 15:36:11 +12:00
|
|
|
constructor(props) {
|
|
|
|
|
super(props);
|
|
|
|
|
this.state = {
|
|
|
|
|
enabled: false,
|
|
|
|
|
seeds: [],
|
|
|
|
|
uri: '',
|
|
|
|
|
error_message: null,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentDidMount() {
|
2020-08-03 07:08:16 +12:00
|
|
|
const {
|
|
|
|
|
uiActions: {
|
|
|
|
|
setWindowTitle,
|
|
|
|
|
},
|
|
|
|
|
radio,
|
|
|
|
|
} = this.props;
|
2019-09-05 15:36:11 +12:00
|
|
|
|
2020-08-03 07:08:16 +12:00
|
|
|
setWindowTitle(i18n('modal.edit_radio.title'));
|
|
|
|
|
|
|
|
|
|
if (radio && radio.enabled) {
|
|
|
|
|
this.loadRadio(radio);
|
2019-09-05 15:36:11 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-12 21:32:50 +13:00
|
|
|
componentDidUpdate = ({ radio: prev_radio }) => {
|
|
|
|
|
const { radio } = this.props;
|
|
|
|
|
if (!prev_radio && radio) this.loadRadio(radio);
|
2019-09-05 15:36:11 +12:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 07:08:16 +12:00
|
|
|
onUriChange = (uri) => {
|
|
|
|
|
this.setState({ uri, error_message: null });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loadRadio = (radio) => {
|
2019-09-05 15:36:11 +12:00
|
|
|
const seeds = [...radio.seed_tracks, ...radio.seed_artists, ...radio.seed_genres];
|
|
|
|
|
this.setState({ seeds, enabled: radio.enabled });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (valid_seeds) {
|
|
|
|
|
this.props.pusherActions.startRadio(this.state.seeds);
|
|
|
|
|
window.history.back();
|
|
|
|
|
} else {
|
2020-07-23 21:07:08 +12:00
|
|
|
this.setState({ error_message: i18n('modal.edit_radio.invalid_seed_uri') });
|
2019-09-05 15:36:11 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (valid_seeds) {
|
|
|
|
|
this.props.pusherActions.updateRadio(this.state.seeds);
|
2019-10-05 09:10:34 +13:00
|
|
|
window.history.back();
|
2019-09-05 15:36:11 +12:00
|
|
|
} else {
|
2020-07-23 21:07:08 +12:00
|
|
|
this.setState({ error_message: i18n('modal.edit_radio.invalid_seed_uri') });
|
2019-09-05 15:36:11 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleStop(e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
this.props.pusherActions.stopRadio();
|
|
|
|
|
this.props.uiActions.closeModal();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 07:08:16 +12:00
|
|
|
addSeed = (e) => {
|
|
|
|
|
const {
|
|
|
|
|
uri,
|
|
|
|
|
seeds,
|
|
|
|
|
} = this.state;
|
|
|
|
|
const {
|
|
|
|
|
coreActions: {
|
|
|
|
|
loadItem,
|
|
|
|
|
},
|
|
|
|
|
} = this.props;
|
|
|
|
|
|
2019-09-05 15:36:11 +12:00
|
|
|
e.preventDefault();
|
|
|
|
|
|
2020-08-03 07:08:16 +12:00
|
|
|
if (uri === '') {
|
2020-07-23 21:07:08 +12:00
|
|
|
this.setState({ error_message: i18n('errors.required') });
|
2019-09-05 15:36:11 +12:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setState({ error_message: null });
|
|
|
|
|
|
2020-08-03 07:08:16 +12:00
|
|
|
const validatedSeeds = Object.assign([], seeds);
|
|
|
|
|
let uris = uri.split(',');
|
2019-09-05 15:36:11 +12:00
|
|
|
|
|
|
|
|
if (uris.length >= 5) {
|
|
|
|
|
uris = uris.slice(0, 5);
|
2020-07-23 21:07:08 +12:00
|
|
|
this.setState({ error_message: i18n('modal.edit_radio.too_many_seeds') });
|
2019-09-05 15:36:11 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < uris.length; i++) {
|
2020-03-03 16:39:37 +13:00
|
|
|
if (uriSource(uris[i]) !== 'spotify') {
|
2020-07-23 21:07:08 +12:00
|
|
|
this.setState({ error_message: i18n('modal.edit_radio.only_spotify_uris') });
|
2019-09-05 15:36:11 +12:00
|
|
|
return;
|
|
|
|
|
} if (seeds.indexOf(uris[i]) > -1) {
|
2020-07-23 21:07:08 +12:00
|
|
|
this.setState({ error_message: i18n('modal.edit_radio.too_many_seeds') });
|
2019-09-05 15:36:11 +12:00
|
|
|
} else {
|
2020-08-03 07:08:16 +12:00
|
|
|
validatedSeeds.push(uris[i]);
|
|
|
|
|
loadItem(uris[i]);
|
2019-09-05 15:36:11 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.setState({
|
2020-08-03 07:08:16 +12:00
|
|
|
seeds: validatedSeeds,
|
2019-09-05 15:36:11 +12:00
|
|
|
uri: '',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 07:08:16 +12:00
|
|
|
removeSeed = (uri) => {
|
|
|
|
|
const {
|
|
|
|
|
seeds: prevSeeds,
|
|
|
|
|
} = this.state;
|
|
|
|
|
|
|
|
|
|
const seeds = prevSeeds.filter((seed) => seed !== uri);
|
2019-09-05 15:36:11 +12:00
|
|
|
this.setState({ seeds });
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 07:08:16 +12:00
|
|
|
mapSeeds = () => {
|
|
|
|
|
const {
|
|
|
|
|
seeds,
|
|
|
|
|
} = this.state;
|
|
|
|
|
const {
|
|
|
|
|
tracks = {},
|
|
|
|
|
artists = {},
|
|
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
|
|
if (!seeds) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return seeds.slice(0, 5).map((uri) => {
|
|
|
|
|
switch (uriType(uri)) {
|
|
|
|
|
case 'artist':
|
|
|
|
|
if (artists[uri]) {
|
|
|
|
|
return artists[uri];
|
2019-09-05 15:36:11 +12:00
|
|
|
}
|
2020-08-03 07:08:16 +12:00
|
|
|
break;
|
|
|
|
|
case 'track':
|
|
|
|
|
if (tracks[uri]) {
|
|
|
|
|
return tracks[uri];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2019-09-05 15:36:11 +12:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 07:08:16 +12:00
|
|
|
return {
|
|
|
|
|
unresolved: true,
|
|
|
|
|
uri,
|
|
|
|
|
};
|
|
|
|
|
});
|
2019-09-05 15:36:11 +12:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 07:08:16 +12:00
|
|
|
render = () => {
|
|
|
|
|
const {
|
|
|
|
|
enabled,
|
|
|
|
|
uri,
|
|
|
|
|
error_message,
|
|
|
|
|
} = this.state;
|
2019-09-05 15:36:11 +12:00
|
|
|
|
2020-08-03 07:08:16 +12:00
|
|
|
const seeds = this.mapSeeds();
|
2019-09-05 15:36:11 +12:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Modal className="modal--edit-radio">
|
2020-07-23 21:07:08 +12:00
|
|
|
<h1>
|
|
|
|
|
<I18n path="modal.edit_radio.title" />
|
|
|
|
|
</h1>
|
|
|
|
|
<h2 className="mid_grey-text">
|
|
|
|
|
<I18n path="modal.edit_radio.subtitle" />
|
|
|
|
|
</h2>
|
2019-09-05 15:36:11 +12:00
|
|
|
|
2020-08-03 07:08:16 +12:00
|
|
|
<form onSubmit={(e) => { (enabled ? this.handleUpdate(e) : this.handleStart(e)); }}>
|
2019-09-05 15:36:11 +12:00
|
|
|
|
|
|
|
|
<div className="field text">
|
2020-07-23 21:07:08 +12:00
|
|
|
<div className="name">
|
|
|
|
|
<I18n path="fields.uri" />
|
|
|
|
|
</div>
|
2019-09-05 15:36:11 +12:00
|
|
|
<div className="input">
|
2020-08-03 07:08:16 +12:00
|
|
|
<TextField
|
|
|
|
|
onChange={this.onUriChange}
|
|
|
|
|
value={uri}
|
2019-09-05 15:36:11 +12:00
|
|
|
/>
|
|
|
|
|
<span className="button discrete add-uri no-hover" onClick={(e) => this.addSeed(e)}>
|
2019-10-03 09:21:38 +13:00
|
|
|
<Icon name="add" />
|
2020-07-23 21:07:08 +12:00
|
|
|
<I18n path="actions.add" />
|
2019-09-05 15:36:11 +12:00
|
|
|
</span>
|
2020-08-03 07:08:16 +12:00
|
|
|
{error_message && <span className="description error">{error_message}</span>}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="field text">
|
|
|
|
|
<div className="name">
|
|
|
|
|
<I18n path="fields.items_to_add.label" />
|
|
|
|
|
</div>
|
|
|
|
|
<div className="input">
|
|
|
|
|
{seeds.length ? (
|
|
|
|
|
<div className="list">
|
|
|
|
|
{seeds.map((seed, index) => (
|
|
|
|
|
<SeedListItem
|
|
|
|
|
key={`${seed}_${index}`}
|
|
|
|
|
seed={seed}
|
|
|
|
|
remove={this.removeSeed}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="text mid_grey-text">
|
|
|
|
|
<I18n path="fields.items_to_add.placeholder" />
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2019-09-05 15:36:11 +12:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="actions centered-text">
|
2020-08-16 20:00:10 +12:00
|
|
|
{this.state.enabled && (
|
|
|
|
|
<Button
|
|
|
|
|
type="destructive"
|
|
|
|
|
size="large"
|
|
|
|
|
onClick={(e) => this.handleStop(e)}
|
|
|
|
|
tracking={{ category: 'Radio', action: 'Stop' }}
|
|
|
|
|
>
|
2020-07-23 21:07:08 +12:00
|
|
|
<I18n path="actions.add" />
|
2020-08-16 20:00:10 +12:00
|
|
|
</Button>
|
|
|
|
|
)}
|
2020-07-23 21:07:08 +12:00
|
|
|
|
|
|
|
|
{this.state.enabled ? (
|
2020-08-16 20:00:10 +12:00
|
|
|
<Button
|
|
|
|
|
type="primary"
|
|
|
|
|
size="large"
|
2020-07-23 21:07:08 +12:00
|
|
|
onClick={(e) => this.handleUpdate(e)}
|
2020-08-16 20:00:10 +12:00
|
|
|
tracking={{ category: 'Radio', action: 'Update' }}
|
2020-07-23 21:07:08 +12:00
|
|
|
>
|
|
|
|
|
<I18n path="actions.save" />
|
2020-08-16 20:00:10 +12:00
|
|
|
</Button>
|
2020-07-23 21:07:08 +12:00
|
|
|
) : (
|
2020-08-16 20:00:10 +12:00
|
|
|
<Button
|
|
|
|
|
type="primary"
|
|
|
|
|
size="large"
|
2020-07-23 21:07:08 +12:00
|
|
|
onClick={(e) => this.handleStart(e)}
|
2020-08-16 20:00:10 +12:00
|
|
|
tracking={{ category: 'Radio', action: 'Start' }}
|
2020-07-23 21:07:08 +12:00
|
|
|
>
|
|
|
|
|
<I18n path="actions.start" />
|
2020-08-16 20:00:10 +12:00
|
|
|
</Button>
|
2020-07-23 21:07:08 +12:00
|
|
|
)}
|
2019-09-05 15:36:11 +12:00
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
</Modal>
|
|
|
|
|
);
|
|
|
|
|
}
|
2018-07-09 19:09:12 +12:00
|
|
|
}
|
|
|
|
|
|
2019-09-05 15:36:11 +12:00
|
|
|
const mapStateToProps = (state, ownProps) => ({
|
|
|
|
|
radio: state.core.radio,
|
|
|
|
|
artists: state.core.artists,
|
|
|
|
|
tracks: state.core.tracks,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const mapDispatchToProps = (dispatch) => ({
|
|
|
|
|
coreActions: bindActionCreators(coreActions, dispatch),
|
|
|
|
|
uiActions: bindActionCreators(uiActions, dispatch),
|
|
|
|
|
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
|
|
|
|
pusherActions: bindActionCreators(pusherActions, dispatch),
|
|
|
|
|
spotifyActions: bindActionCreators(spotifyActions, dispatch),
|
|
|
|
|
});
|
|
|
|
|
|
2019-10-03 09:21:38 +13:00
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(EditRadio);
|