All views done this time; Language file mapping for modals.. Will need to do destructuring in second sweep

This commit is contained in:
James Barnsley
2020-07-19 20:41:14 +12:00
parent 9f186d281c
commit 2de98afee4
21 changed files with 1807 additions and 1330 deletions

View File

@ -11,43 +11,53 @@ import * as spotifyActions from '../../services/spotify/actions';
import {
isLoading,
} from '../../util/helpers';
import { i18n, I18n } from '../../locale';
import { indexToArray } from '../../util/arrays';
class DiscoverCategories extends React.Component {
componentDidMount() {
const {
categories,
spotifyActions: {
getCategories,
},
uiActions: {
setWindowTitle,
},
} = this.props;
// Check for an empty category index, or where we've only got one loaded
// This would be the case if you've refreshed from within a category and only loaded
// the single record.
if (!this.props.categories || Object.keys(this.props.categories).length <= 1) {
this.props.spotifyActions.getCategories();
if (!categories || Object.keys(categories).length <= 1) {
getCategories();
}
this.props.uiActions.setWindowTitle('Genre / Mood');
setWindowTitle(i18n('discover.categories.title'));
}
render() {
if (isLoading(this.props.load_queue, ['spotify_browse/categories'])) {
render = () => {
const {
load_queue,
categories: categoriesProp,
uiActions,
} = this.props;
if (isLoading(load_queue, ['spotify_browse/categories'])) {
return (
<div className="view discover-categories-view">
<Header icon="grid" title="Genre / Mood" />
<Header icon="grid" title={i18n('discover.categories.title')} />
<Loader body loading />
</div>
);
}
// convert categories object into simple array
const categories = [];
if (this.props.categories) {
for (const key in this.props.categories) {
if (this.props.categories.hasOwnProperty(key)) {
categories.push(this.props.categories[key]);
}
}
}
const categories = indexToArray(categoriesProp);
return (
<div className="view discover-categories-view">
<Header uiActions={this.props.uiActions}>
<Header uiActions={uiActions}>
<Icon name="mood" type="material" />
Genre / Mood
<I18n path="discover.categories.title" />
</Header>
<section className="content-wrapper grid-wrapper">
<CategoryGrid categories={categories} />
@ -57,14 +67,7 @@ class DiscoverCategories extends React.Component {
}
}
/**
* Export our component
*
* We also integrate our global store, using connect()
* */
const mapStateToProps = (state, ownProps) => ({
const mapStateToProps = (state) => ({
categories: state.spotify.categories,
load_queue: state.ui.load_queue,
});

View File

@ -11,6 +11,7 @@ import * as uiActions from '../../services/ui/actions';
import * as spotifyActions from '../../services/spotify/actions';
import { isLoading } from '../../util/helpers';
import { collate } from '../../util/format';
import { i18n } from '../../locale';
class DiscoverCategory extends React.Component {
componentDidMount() {
@ -39,57 +40,93 @@ class DiscoverCategory extends React.Component {
if (!prevCategory && category) this.setWindowTitle(category);
}
setWindowTitle(category = this.props.category) {
setWindowTitle = (category = this.props.category) => {
const {
uiActions: { setWindowTitle },
} = this.props;
if (category) {
this.props.uiActions.setWindowTitle(category.name);
setWindowTitle(category.name);
} else {
this.props.uiActions.setWindowTitle('Genre / Mood');
setWindowTitle(i18n('discover.category.title'));
}
}
loadCategory() {
if (!this.props.category) {
this.props.spotifyActions.getCategory(this.props.match.params.id);
loadCategory = () => {
const {
category,
match: {
params: { id },
},
spotifyActions: {
getCategory,
getCategoryPlaylists,
},
} = this.props;
if (!category) {
getCategory(id);
}
if (!this.props.category.playlists_uris) {
this.props.spotifyActions.getCategoryPlaylists(this.props.match.params.id);
if (!category.playlists_uris) {
getCategoryPlaylists(id);
}
}
loadMore() {
this.props.spotifyActions.getMore(
this.props.category.playlists_more,
loadMore = () => {
const {
spotifyActions: {
getMore,
},
category: {
playlists_more,
},
match: {
params: {
id,
},
},
} = this.props;
getMore(
playlists_more,
null,
{
type: 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED_MORE',
uri: `category:${this.props.match.params.id}`,
uri: `category:${id}`,
},
);
}
render() {
if (isLoading(this.props.load_queue, ['spotify_browse/categories/'])) {
render = () => {
const {
category: categoryProp,
playlists,
load_queue,
uiActions,
} = this.props;
if (isLoading(load_queue, ['spotify_browse/categories/'])) {
return (
<div className="view discover-categories-view">
<Header>
<Icon name="mood" type="material" />
{(this.props.category ? this.props.category.name : 'Category')}
{(categoryProp ? categoryProp.name : i18n('discover.category.category'))}
</Header>
<Loader body loading />
</div>
);
}
if (!this.props.category) {
if (!categoryProp) {
return null;
}
const category = collate(this.props.category, { playlists: this.props.playlists });
const category = collate(categoryProp, { playlists });
return (
<div className="view discover-categories-view">
<Header uiActions={this.props.uiActions}>
<Header uiActions={uiActions}>
<Icon name="mood" type="material" />
{category.name}
</Header>
@ -100,7 +137,7 @@ class DiscoverCategory extends React.Component {
<LazyLoadListener
loadKey={category.playlists_more}
showLoader={category.playlists_more}
loadMore={() => this.loadMore()}
loadMore={this.loadMore}
/>
</div>
</div>

View File

@ -10,6 +10,7 @@ import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import * as spotifyActions from '../../services/spotify/actions';
import { isLoading } from '../../util/helpers';
import { i18n, I18n } from '../../locale';
class DiscoverFeatured extends React.Component {
componentDidMount() {
@ -23,7 +24,7 @@ class DiscoverFeatured extends React.Component {
},
} = this.props;
setWindowTitle('Featured playlists');
setWindowTitle(i18n('discover.featured.title'));
if (!featured_playlists) getFeaturedPlaylists();
}
@ -40,7 +41,7 @@ class DiscoverFeatured extends React.Component {
getFeaturedPlaylists();
}
handleContextMenu(e, item) {
handleContextMenu = (e, item) => {
const {
uiActions: {
showContextMenu,
@ -70,7 +71,7 @@ class DiscoverFeatured extends React.Component {
<div className="view discover-featured-view preserve-3d">
<Header className="overlay" uiActions={uiActions}>
<Icon name="star" type="material" />
Featured playlists
<I18n path="discover.featured.title" />
</Header>
<Loader body loading />
</div>
@ -90,7 +91,7 @@ class DiscoverFeatured extends React.Component {
const options = (
<a className="button button--no-hover" onClick={this.onRefresh}>
<Icon name="refresh" />
Refresh
<I18n path="actions.refresh" />
</a>
);
@ -98,7 +99,7 @@ class DiscoverFeatured extends React.Component {
<div className="view discover-featured-view preserve-3d">
<Header uiActions={uiActions} options={options}>
<Icon name="star" type="material" />
Featured playlists
<I18n path="discover.featured.title" />
</Header>
<section className="content-wrapper grid-wrapper">
{items && <PlaylistGrid playlists={items} />}

View File

@ -12,20 +12,37 @@ import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import * as spotifyActions from '../../services/spotify/actions';
import { isLoading } from '../../util/helpers';
import { collate } from '../../util/format';
import { i18n, I18n } from '../../locale';
class DiscoverNewReleases extends React.Component {
componentDidMount() {
this.props.uiActions.setWindowTitle('New releases');
const {
new_releases,
uiActions: {
setWindowTitle,
},
spotifyActions: {
getNewReleases,
},
} = this.props;
if (!this.props.new_releases) {
this.props.spotifyActions.getNewReleases();
setWindowTitle(i18n('discover.new_releases.title'));
if (!new_releases) {
getNewReleases();
}
}
loadMore() {
this.props.spotifyActions.getMore(
this.props.new_releases_more,
loadMore = () => {
const {
new_releases_more,
spotifyActions: {
getMore,
},
} = this.props;
getMore(
new_releases_more,
null,
{
type: 'SPOTIFY_NEW_RELEASES_LOADED',
@ -33,19 +50,36 @@ class DiscoverNewReleases extends React.Component {
);
}
playAlbum(e, album) {
this.props.mopidyActions.playURIs([album.uri], album.uri);
playAlbum = (album) => {
const { mopidyActions: { playURIs } } = this.props;
playURIs([album.uri], album.uri);
}
refresh = () => {
const {
uiActions: {
hideContextMenu,
},
spotifyActions: {
getNewReleases,
},
} = this.props;
hideContextMenu();
getNewReleases();
}
handleContextMenu(e, item) {
const { uriActions: { showContextMenu } } = this.props;
e.preventDefault();
const data = {
showContextMenu({
e,
context: 'album',
uris: [item.uri],
items: [item],
};
this.props.uiActions.showContextMenu(data);
});
}
renderIntro = ({ images: { large } = {} } = {}) => (
@ -54,13 +88,21 @@ class DiscoverNewReleases extends React.Component {
</div>
);
render() {
if (isLoading(this.props.load_queue, ['spotify_browse/new-releases'])) {
render = () => {
const {
load_queue,
new_releases,
albums: albumsProp,
new_releases_more,
uiActions,
} = this.props;
if (isLoading(load_queue, ['spotify_browse/new-releases'])) {
return (
<div className="view discover-new-releases-view">
<Header>
<Icon name="new_releases" type="material" />
New releases
<I18n path="discover.new_releases.title" />
</Header>
<Loader body loading />
</div>
@ -68,41 +110,41 @@ class DiscoverNewReleases extends React.Component {
}
const albums = [];
if (this.props.new_releases) {
for (const uri of this.props.new_releases) {
if (this.props.albums.hasOwnProperty(uri)) {
albums.push(this.props.albums[uri]);
if (new_releases) {
for (const uri of new_releases) {
if (albumsProp.hasOwnProperty(uri)) {
albums.push(albumsProp[uri]);
}
}
}
const options = (
<a className="button button--no-hover" onClick={(e) => { this.props.uiActions.hideContextMenu(); this.props.spotifyActions.getNewReleases(); }}>
<a className="button button--no-hover" onClick={this.refresh}>
<Icon name="refresh" />
Refresh
<I18n path="actions.refresh" />
</a>
);
return (
<div className="view discover-new-releases-view preserve-3d">
<Header options={options} uiActions={this.props.uiActions}>
<Header options={options} uiActions={uiActions}>
<Icon name="new_releases" type="material" />
New releases
<I18n path="discover.new_releases.title" />
</Header>
<section className="content-wrapper grid-wrapper">
<AlbumGrid albums={albums} />
</section>
<LazyLoadListener
loadKey={this.props.new_releases_more}
showLoader={this.props.new_releases_more}
loadMore={() => this.loadMore()}
loadKey={new_releases_more}
showLoader={new_releases_more}
loadMore={this.loadMore}
/>
</div>
);
}
}
const mapStateToProps = (state, ownProps) => ({
const mapStateToProps = (state) => ({
theme: state.ui.theme,
load_queue: state.ui.load_queue,
artists: state.core.artists,

View File

@ -22,7 +22,8 @@ import {
uriType,
titleCase,
} from '../../util/helpers';
import { arrayOf } from '../../util/arrays';
import { arrayOf, indexToArray } from '../../util/arrays';
import { i18n, I18n } from '../../locale';
class Discover extends React.Component {
constructor(props) {
@ -150,15 +151,25 @@ class Discover extends React.Component {
}
componentDidMount() {
this.props.uiActions.setWindowTitle('Discover');
const {
uiActions: {
setWindowTitle,
},
match: {
params: {
seeds,
},
},
} = this.props;
// We have seeds provided in the URL
if (this.props.match.params.seeds) {
this.handleURLSeeds(this.props.match.params.seeds);
setWindowTitle(i18n('discover.recommendations.title'));
if (seeds) {
this.handleURLSeeds();
}
}
componentDiUpdate = ({
componentDidUpdate = ({
match: {
params: {
seeds: prevSeeds,
@ -172,63 +183,92 @@ class Discover extends React.Component {
},
},
} = this.props;
if (prevSeeds !== seeds) this.handleURLSeeds(seeds);
if (prevSeeds !== seeds) this.handleURLSeeds();
}
handleContextMenu(e) {
var uri = 'iris:discover';
if (this.state.seeds) {
handleContextMenu = (e) => {
const {
recommendations: {
tracks_uris,
},
uiActions: {
showContextMenu,
},
tracks: tracksProp,
} = this.props;
const {
seeds,
} = this.state;
let uri = 'iris:discover';
if (seeds) {
uri += ':';
for (var i = 0; i < this.state.seeds.length; i++) {
for (let i = 0; i < seeds.length; i++) {
if (i > 0) {
uri += ',';
}
uri += this.state.seeds[i].split(':').join('_');
uri += seeds[i].split(':').join('_');
}
}
const tracks = [];
if (this.props.recommendations.tracks_uris && this.props.tracks) {
for (var i = 0; i < this.props.recommendations.tracks_uris.length; i++) {
var uri = this.props.recommendations.tracks_uris[i];
if (this.props.tracks.hasOwnProperty(uri)) {
tracks.push(this.props.tracks[uri]);
}
}
}
const tracks = indexToArray(tracksProp, tracks_uris);
const data = {
showContextMenu({
e,
context: 'track',
items: tracks,
uris: arrayOf('uri', tracks),
};
this.props.uiActions.showContextMenu(data);
});
}
handleURLSeeds(seeds_string = this.props.match.params.seeds) {
handleURLSeeds = () => {
const {
spotifyActions: {
getArtist,
getTrack,
},
match: {
params: {
seeds: seedsProp,
},
},
} = this.props;
// Rejoin if we've had to uri-encode these as strings
// We'd need to do this if our URL has been encoded so the whole URL can become
// it's own URI (eg iris:discover:spotify_artist_1234) where we can't use ":"
const seeds = seeds_string.split('_').join(':').split(',');
const seeds = seedsProp.split('_').join(':').split(',');
for (let i = 0; i < seeds.length; i++) {
switch (uriType(seeds[i])) {
case 'artist':
this.props.spotifyActions.getArtist(seeds[i]);
getArtist(seeds[i]);
break;
case 'track':
this.props.spotifyActions.getTrack(seeds[i]);
getTrack(seeds[i]);
break;
default:
break;
}
}
this.setState({ seeds });
this.getRecommendations(seeds);
this.setState(
{ seeds },
() => this.getRecommendations(),
);
}
getRecommendations(seeds = this.state.seeds, tunabilities = this.state.tunabilities) {
getRecommendations = () => {
const {
seeds,
tunabilities,
} = this.state;
const {
spotifyActions: {
getRecommendations: doGetRecommendations,
},
} = this.props;
if (seeds.length > 0) {
const digested_tunabilities = {};
for (const key in tunabilities) {
@ -247,37 +287,53 @@ class Discover extends React.Component {
digested_tunabilities[`${key}_min`] = min.toString();
}
}
this.props.spotifyActions.getRecommendations(seeds, 50, digested_tunabilities);
doGetRecommendations(seeds, 50, digested_tunabilities);
}
}
playTracks() {
this.props.mopidyActions.playURIs(this.props.recommendations.tracks_uris);
playTracks = () => {
const {
mopidyActions: {
playURIs,
},
recommendations: {
tracks_uris,
},
} = this.props;
playURIs(tracks_uris);
}
removeSeed(index) {
removeSeed = (index) => {
const { seeds } = this.state;
seeds.splice(index, 1);
this.setState({ seeds });
}
handleSelect(e, uri) {
handleSelect = (e, uri) => {
const { seeds } = this.state;
seeds.push(uri);
this.setState({ seeds });
}
renderSeeds() {
renderSeeds = () => {
const {
tracks,
artists,
} = this.props;
const {
seeds,
} = this.state;
const seeds_objects = [];
if (this.state.seeds.length > 0) {
for (let i = 0; i < this.state.seeds.length; i++) {
const uri = this.state.seeds[i];
if (seeds.length > 0) {
for (let i = 0; i < seeds.length; i++) {
const uri = seeds[i];
switch (uriType(uri)) {
case 'track':
if (typeof (this.props.tracks[uri]) !== 'undefined') {
seeds_objects.push(this.props.tracks[uri]);
if (typeof (tracks[uri]) !== 'undefined') {
seeds_objects.push(tracks[uri]);
} else {
seeds_objects.push({
name: 'Loading...',
@ -285,10 +341,9 @@ class Discover extends React.Component {
});
}
break;
case 'artist':
if (typeof (this.props.artists[uri]) !== 'undefined') {
seeds_objects.push(this.props.artists[uri]);
if (typeof (artists[uri]) !== 'undefined') {
seeds_objects.push(artists[uri]);
} else {
seeds_objects.push({
name: 'Loading...',
@ -296,7 +351,6 @@ class Discover extends React.Component {
});
}
break;
case 'genre':
var name = getFromUri('genreid', uri);
seeds_objects.push({
@ -304,6 +358,8 @@ class Discover extends React.Component {
uri,
});
break;
default:
break;
}
}
}
@ -311,22 +367,26 @@ class Discover extends React.Component {
return (
<div className="seeds">
{
seeds_objects.map((seed, index) => {
const type = uriType(seed.uri);
let images = null;
if (seed.images) {
if (type == 'artist') {
if (seed.images.length > 0) {
images = seed.images[0];
}
} else {
images = seed.images;
}
}
seeds_objects.map((seed, index) => {
const type = uriType(seed.uri);
let images = null;
if (seed.images) {
if (type === 'artist') {
if (seed.images.length > 0) {
images = seed.images[0];
}
} else {
images = seed.images;
}
}
return (
<div className={`seed${seed.images ? ' has-thumbnail' : ''}`} key={seed.uri}>
{images ? <URILink className="thumbnail-wrapper" type={type} uri={seed.uri}><Thumbnail images={images} circle={seed.type == 'artist'} size="small" /></URILink> : null}
{images && (
<URILink className="thumbnail-wrapper" type={type} uri={seed.uri}>
<Thumbnail images={images} circle={seed.type === 'artist'} size="small" />
</URILink>
)}
<div className="seed__details">
<div className="seed__label">
<span className="seed__label__text">{titleCase(type)}</span>
@ -342,19 +402,19 @@ class Discover extends React.Component {
);
}
setTunability(name, value) {
setTunability = (name, value) => {
const { tunabilities } = this.state;
tunabilities[name].value = value;
this.setState({ tunabilities });
}
toggleTunability(name) {
toggleTunability = (name) => {
const { tunabilities } = this.state;
tunabilities[name].enabled = !tunabilities[name].enabled;
this.setState({ tunabilities });
}
renderTunabilities() {
renderTunabilities = () => {
const addable_tunabilities = [];
const enabled_tunabilities = [];
for (const key in this.state.tunabilities) {
@ -382,7 +442,7 @@ class Discover extends React.Component {
<div className="field tunability range" key={tunability.name}>
<div className="tunability__label">
{titleCase(tunability.name)}
<span className="remove" onClick={(e) => this.toggleTunability(tunability.name)}>
<span className="remove" onClick={() => this.toggleTunability(tunability.name)}>
<Icon name="close" />
</span>
</div>
@ -401,38 +461,51 @@ class Discover extends React.Component {
);
}
renderResults() {
// Results not in
if (!this.props.recommendations || this.props.recommendations.albums_uris === undefined || this.props.recommendations.artists_uris === undefined) {
renderResults = () => {
const {
recommendations: {
tracks_uris,
albums_uris,
artists_uris,
} = {},
tracks: tracksProp,
artists: artistsProp,
albums: albumsProp,
} = this.props;
const {
seeds,
} = this.state;
if (!albums_uris === undefined || artists_uris === undefined) {
return <div className="content-wrapper recommendations-results" />;
}
const tracks = [];
if (this.props.recommendations.tracks_uris && this.props.tracks) {
for (var i = 0; i < this.props.recommendations.tracks_uris.length; i++) {
var uri = this.props.recommendations.tracks_uris[i];
if (this.props.tracks.hasOwnProperty(uri)) {
tracks.push(this.props.tracks[uri]);
if (tracks_uris && tracksProp) {
for (var i = 0; i < tracks_uris.length; i++) {
var uri = tracks_uris[i];
if (tracksProp.hasOwnProperty(uri)) {
tracks.push(tracksProp[uri]);
}
}
}
const artists = [];
if (this.props.recommendations.artists_uris && this.props.artists) {
for (var i = 0; i < this.props.recommendations.artists_uris.length; i++) {
var uri = this.props.recommendations.artists_uris[i];
if (this.props.artists.hasOwnProperty(uri)) {
artists.push(this.props.artists[uri]);
if (artists_uris && artistsProp) {
for (var i = 0; i < artists_uris.length; i++) {
var uri = artists_uris[i];
if (artistsProp.hasOwnProperty(uri)) {
artists.push(artistsProp[uri]);
}
}
}
const albums = [];
if (this.props.recommendations.albums_uris && this.props.albums) {
for (var i = 0; i < this.props.recommendations.albums_uris.length; i++) {
var uri = this.props.recommendations.albums_uris[i];
if (this.props.albums.hasOwnProperty(uri)) {
albums.push(this.props.albums[uri]);
if (albums_uris && albumsProp) {
for (var i = 0; i < albums_uris.length; i++) {
var uri = albums_uris[i];
if (albumsProp.hasOwnProperty(uri)) {
albums.push(albumsProp[uri]);
}
}
}
@ -443,13 +516,13 @@ class Discover extends React.Component {
}
var uri = 'iris:discover';
if (this.state.seeds) {
if (seeds) {
uri += ':';
for (var i = 0; i < this.state.seeds.length; i++) {
for (var i = 0; i < seeds.length; i++) {
if (i > 0) {
uri += ',';
}
uri += this.state.seeds[i].split(':').join('_');
uri += seeds[i].split(':').join('_');
}
}
@ -458,10 +531,12 @@ class Discover extends React.Component {
<section className="col col--w70 tracks">
<h4>
Tracks
<I18n path="discover.recommendations.tracks" />
<div className="pull-right">
<ContextMenuTrigger onTrigger={(e) => this.handleContextMenu(e)} />
<button className="button button--primary" onClick={(e) => this.playTracks(e)}>Play all</button>
<ContextMenuTrigger onTrigger={this.handleContextMenu} />
<button className="button button--primary" onClick={this.playTracks} type="button">
<I18n path="actions.play_all" />
</button>
</div>
</h4>
<TrackList className="discover-track-list" uri={uri} tracks={tracks} />
@ -471,13 +546,13 @@ class Discover extends React.Component {
<div className="col col--w25 others">
<section>
<h4>Artists</h4>
<RelatedArtists artists={artists} uiActions={this.props.uiActions} />
<h4><I18n path="discover.recommendations.artists" /></h4>
<RelatedArtists artists={artists} uiActions={uiActions} />
</section>
<br />
<br />
<section>
<h4>Albums</h4>
<h4><I18n path="discover.recommendations.albums" /></h4>
<AlbumGrid className="grid--mini" albums={albums} />
</section>
</div>
@ -486,14 +561,22 @@ class Discover extends React.Component {
);
}
render() {
const is_loading = isLoading(this.props.load_queue, ['spotify_recommendations']);
render = () => {
const {
load_queue,
theme,
} = this.props;
const {
tunabilities,
seeds,
} = this.state;
const is_loading = isLoading(load_queue, ['spotify_recommendations']);
const addable_tunabilities = [];
for (const key in this.state.tunabilities) {
if (this.state.tunabilities.hasOwnProperty(key)) {
if (tunabilities.hasOwnProperty(key)) {
const tunability = {
...this.state.tunabilities[key],
...tunabilities[key],
name: key,
};
@ -509,30 +592,39 @@ class Discover extends React.Component {
return (
<div className="view discover-view preserve-3d">
<div className="intro preserve-3d">
{this.props.theme == 'dark' && <Parallax image="/iris/assets/backgrounds/discover.jpg" />}
{theme === 'dark' && <Parallax image="/iris/assets/backgrounds/discover.jpg" />}
<div className="intro__liner">
<h1>Explore new music</h1>
<h2>Add seeds and musical properties below to build your sound</h2>
<h1><I18n path="discover.recommendations.body_title" /></h1>
<h2><I18n path="discover.recommendations.body_subtitle" /></h2>
<div className="intro__parameters">
{this.renderSeeds()}
{this.renderTunabilities()}
{this.state.seeds.length > 5 ? <p className="message error">Too many seeds! You can use up to a total of 5 seed tracks, artists and genres.</p> : null}
{seeds.length > 5 && (
<p className="message error">
<I18n path="discover.recommendations.too_many_seeds" />
</p>
)}
</div>
<div className="intro__actions">
<AddSeedField onSelect={(e, uri) => this.handleSelect(e, uri)} />
<DropdownField className="add-properties" name="Properties" options={addable_tunabilities} no_status_icon button="default" handleChange={(val) => { this.toggleTunability(val); }} />
<DropdownField
className="add-properties"
name="Properties"
options={addable_tunabilities}
no_status_icon
button="default"
handleChange={this.toggleTunability}
/>
<div className="intro__actions__separator" />
<span className={`submit button button--primary button--large${is_loading ? ' button--working' : ''}`} onClick={(e) => this.getRecommendations()}>
<span
className={`submit button button--primary button--large${is_loading ? ' button--working' : ''}`}
onClick={this.getRecommendations}
>
<Icon name="explore" />
&nbsp;
Find recommendations
<I18n path="discover.recommendations.find_recommendations" afterContent>
{' '}
</I18n>
</span>
</div>
</div>
@ -545,7 +637,7 @@ class Discover extends React.Component {
}
}
const mapStateToProps = (state, ownProps) => ({
const mapStateToProps = (state) => ({
theme: state.ui.theme,
albums: state.core.albums,
artists: state.core.artists,