From a2d326563d4b5935eb7a8f9b1b89c6893bffea90 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Fri, 2 Jun 2017 09:31:05 +1200 Subject: [PATCH] Discover moved to recommendations; URL handles context loading --- src/js/components/AddSeedField.js | 18 +++- src/js/components/ContextMenu.js | 14 +++ src/js/components/Sidebar.js | 2 +- src/js/index.js | 4 +- src/js/services/spotify/actions.js | 18 ++-- src/js/services/spotify/middleware.js | 26 +++++ src/js/services/spotify/reducer.js | 9 +- src/js/services/ui/actions.js | 52 +++++++++ src/js/services/ui/reducer.js | 14 +-- ...Discover.js => DiscoverRecommendations.js} | 100 ++++++++++++++---- 10 files changed, 214 insertions(+), 43 deletions(-) rename src/js/views/discover/{Discover.js => DiscoverRecommendations.js} (68%) diff --git a/src/js/components/AddSeedField.js b/src/js/components/AddSeedField.js index e36cfb0a..b0797a9f 100755 --- a/src/js/components/AddSeedField.js +++ b/src/js/components/AddSeedField.js @@ -6,6 +6,7 @@ import { Link, hashHistory } from 'react-router' import ArtistSentence from './ArtistSentence' import * as helpers from '../helpers' +import * as uiActions from '../services/ui/actions' import * as spotifyActions from '../services/spotify/actions' class AddSeedField extends React.Component{ @@ -59,8 +60,20 @@ class AddSeedField extends React.Component{ handleSelect(e,item){ this.setState({value: ''}) - this.props.onSelect(e,item) + this.props.onSelect(e,item.uri) this.props.spotifyActions.clearAutocompleteResults(this.id) + + // Add our selected item to our global index + switch (helpers.uriType(item.uri)){ + + case 'artist': + this.props.uiActions.albumLoaded(item.uri,item) + break + + case 'track': + this.props.uiActions.trackLoaded(item.uri,item) + break + } } results(){ @@ -123,13 +136,14 @@ class AddSeedField extends React.Component{ const mapStateToProps = (state, ownProps) => { return { - genres: (state.spotify.genres ? state.spotify.genres : null), + genres: (state.ui.genres ? state.ui.genres : null), results: (state.spotify.autocomplete_results ? state.spotify.autocomplete_results : {}) } } const mapDispatchToProps = (dispatch) => { return { + uiActions: bindActionCreators(uiActions, dispatch), spotifyActions: bindActionCreators(spotifyActions, dispatch) } } diff --git a/src/js/components/ContextMenu.js b/src/js/components/ContextMenu.js index 1b84976b..ba588974 100755 --- a/src/js/components/ContextMenu.js +++ b/src/js/components/ContextMenu.js @@ -194,6 +194,11 @@ class ContextMenu extends React.Component{ this.props.pusherActions.startRadio(this.props.menu.uris) } + goToRecommendations(e){ + this.props.uiActions.hideContextMenu() + hashHistory.push( global.baseURL +'discover/recommendations/'+ this.props.menu.items[0].uri ) + } + goToArtist(e){ if (!this.props.menu.items || this.props.menu.items.length <= 0 || !this.props.menu.items[0].artists || this.props.menu.items[0].artists.length <= 0){ return null @@ -399,6 +404,14 @@ class ContextMenu extends React.Component{ ) + var go_to_recommendations = ( + + this.goToRecommendations(e)}> + More like this + + + ) + var start_radio = ( this.startRadio(e)}> @@ -451,6 +464,7 @@ class ContextMenu extends React.Component{
{start_radio} {this.canBeInLibrary() ? toggle_in_library : null} + {go_to_recommendations} {copy_uris}
) diff --git a/src/js/components/Sidebar.js b/src/js/components/Sidebar.js index 0f8af507..747918c6 100755 --- a/src/js/components/Sidebar.js +++ b/src/js/components/Sidebar.js @@ -39,7 +39,7 @@ class Sidebar extends React.Component{
Discover - + Discover diff --git a/src/js/index.js b/src/js/index.js index 9dcd0c76..d7588490 100755 --- a/src/js/index.js +++ b/src/js/index.js @@ -23,7 +23,7 @@ import Settings from './views/Settings' import Debug from './views/Debug' import Search from './views/Search' -import Discover from './views/discover/Discover' +import DiscoverRecommendations from './views/discover/DiscoverRecommendations' import DiscoverFeatured from './views/discover/DiscoverFeatured' import DiscoverCategories from './views/discover/DiscoverCategories' import DiscoverCategory from './views/discover/DiscoverCategory' @@ -66,7 +66,7 @@ ReactDOM.render( - + diff --git a/src/js/services/spotify/actions.js b/src/js/services/spotify/actions.js index 22601191..65190f52 100755 --- a/src/js/services/spotify/actions.js +++ b/src/js/services/spotify/actions.js @@ -498,14 +498,16 @@ export function getAutocompleteResults(field_id, query, types = ['album','artist .then(response => { var genres = [] if (genre_included){ - var available_genres = getState().spotify.genres - for (var i = 0; i < available_genres.length; i++){ - if (available_genres[i].includes(query)){ - var genre = available_genres[i] - genres.push({ - name: (genre.charAt(0).toUpperCase()+genre.slice(1)).replace('-',' '), - uri: 'spotify:genre:'+genre - }) + var available_genres = getState().ui.genres + if (available_genres){ + for (var i = 0; i < available_genres.length; i++){ + if (available_genres[i].includes(query)){ + var genre = available_genres[i] + genres.push({ + name: (genre.charAt(0).toUpperCase()+genre.slice(1)).replace('-',' '), + uri: 'spotify:genre:'+genre + }) + } } } } diff --git a/src/js/services/spotify/middleware.js b/src/js/services/spotify/middleware.js index cabe7ff5..96e10ac8 100755 --- a/src/js/services/spotify/middleware.js +++ b/src/js/services/spotify/middleware.js @@ -273,6 +273,32 @@ const SpotifyMiddleware = (function(){ }); break + case 'SPOTIFY_FAVORITES_LOADED': + if (action.artists.length > 0){ + store.dispatch({ + type: 'ARTISTS_LOADED', + artists: action.artists + }) + action.artists_uris = helpers.asURIs(action.artists) + } + if (action.tracks.length > 0){ + store.dispatch({ + type: 'TRACKS_LOADED', + tracks: action.tracks + }) + action.tracks_uris = helpers.asURIs(action.tracks) + } + next(action) + break + + case 'SPOTIFY_TRACK_LOADED': + store.dispatch({ + type: 'TRACK_LOADED', + key: action.data.uri, + track: action.data + }); + break + case 'SPOTIFY_SEARCH_RESULTS_LOADED_MORE_TRACKS': store.dispatch({ type: 'SEARCH_RESULTS_LOADED', diff --git a/src/js/services/spotify/reducer.js b/src/js/services/spotify/reducer.js index 0ad9dfb9..9a1d16a3 100755 --- a/src/js/services/spotify/reducer.js +++ b/src/js/services/spotify/reducer.js @@ -1,4 +1,6 @@ +import * as helpers from '../../helpers' + export default function reducer(spotify = {}, action){ switch (action.type) { @@ -179,9 +181,6 @@ export default function reducer(spotify = {}, action){ if( !action.data ) return Object.assign({}, spotify, { discover: [] }) return Object.assign({}, spotify, { discover: [...spotify.discover, ...[action.data]] }) - case 'SPOTIFY_GENRES_LOADED': - return Object.assign({}, spotify, {genres: action.genres}) - case 'SPOTIFY_RECOMMENDATIONS_LOADED': return Object.assign( {}, @@ -199,8 +198,8 @@ export default function reducer(spotify = {}, action){ {}, spotify, { - favorite_artists: action.artists, - favorite_tracks: action.tracks + favorite_artists: action.artists_uris, + favorite_tracks: action.tracks_uris }) case 'SPOTIFY_AUTOCOMPLETE_LOADING': diff --git a/src/js/services/ui/actions.js b/src/js/services/ui/actions.js index 2d6ef3db..bcfb56c5 100755 --- a/src/js/services/ui/actions.js +++ b/src/js/services/ui/actions.js @@ -210,6 +210,57 @@ export function addTracksToPlaylist( uri, tracks_uris ){ } +/** + * Assets loaded + **/ + +export function albumLoaded(key,album){ + return { + type: 'ALBUM_LOADED', + key: key, + album: album + } +} + +export function albumsLoaded(albums){ + return { + type: 'ALBUMS_LOADED', + albums: albums + } +} + +export function artistLoaded(key,artist){ + return { + type: 'ARTIST_LOADED', + key: key, + artist: artist + } +} + +export function artistsLoaded(artists){ + return { + type: 'ALBUMS_LOADED', + artists: artists + } +} + +export function trackLoaded(key,track){ + return { + type: 'TRACK_LOADED', + key: key, + track: track + } +} + +export function tracksLoaded(tracks){ + return { + type: 'TRACKS_LOADED', + tracks: tracks + } +} + + + /** * Modal * @@ -268,6 +319,7 @@ export function removeNotification(key){ } + /** * Loaders **/ diff --git a/src/js/services/ui/reducer.js b/src/js/services/ui/reducer.js index 799c1ac0..8234150c 100755 --- a/src/js/services/ui/reducer.js +++ b/src/js/services/ui/reducer.js @@ -105,12 +105,6 @@ export default function reducer(ui = {}, action){ return Object.assign({}, ui, { current_tracklist: tracklist }); - case 'SPOTIFY_TRACK_LOADED': - if( !action.data ) return ui - - var current_track = Object.assign({}, ui.current_track, action.data) - return Object.assign({}, ui, { current_track: current_track }); - case 'MOPIDY_CURRENTTLTRACK': if( !action.data ) return ui @@ -605,6 +599,14 @@ export default function reducer(ui = {}, action){ return Object.assign({}, ui, { library_playlists: items }); + /** + * Genres + **/ + + case 'SPOTIFY_GENRES_LOADED': + return Object.assign({}, ui, {genres: action.genres}) + + /** * Search results **/ diff --git a/src/js/views/discover/Discover.js b/src/js/views/discover/DiscoverRecommendations.js similarity index 68% rename from src/js/views/discover/Discover.js rename to src/js/views/discover/DiscoverRecommendations.js index a41a6927..0675d05c 100755 --- a/src/js/views/discover/Discover.js +++ b/src/js/views/discover/DiscoverRecommendations.js @@ -23,10 +23,7 @@ class Discover extends React.Component{ this.state = { seeds: [ - { - uri: 'spotify:genre:chill', - name: 'Chill' - } + 'spotify:genre:chill' ], add_seed: '', adding_seed: false @@ -34,10 +31,36 @@ class Discover extends React.Component{ } componentDidMount(){ - if (this.props.authorized){ - this.props.spotifyActions.getFavorites() + + // We have seeds provided in the URL + if (this.props.params.seeds){ + + var seeds = this.props.params.seeds.split(',') + // TODO: lookup these seeds + + for (var i = 0; i < seeds.length; i++){ + switch (helpers.uriType(seeds[i])){ + + case 'artist': + this.props.spotifyActions.getArtist(seeds[i]) + break + + case 'track': + this.props.spotifyActions.getTrack(seeds[i]) + break + } + } + + this.setState({seeds: seeds}) + this.getRecommendations(seeds) + + // BAU } else { - this.getRecommendations() + if (this.props.authorized){ + this.props.spotifyActions.getFavorites() + } else { + this.getRecommendations() + } } } @@ -57,8 +80,7 @@ class Discover extends React.Component{ getRecommendations(seeds = this.state.seeds){ if (seeds.length > 0){ - var uris = helpers.asURIs(seeds) - this.props.spotifyActions.getRecommendations(uris, 50) + this.props.spotifyActions.getRecommendations(seeds, 50) } } @@ -69,32 +91,70 @@ class Discover extends React.Component{ this.getRecommendations(seeds) } - handleSelect(e,item){ + handleSelect(e,uri){ var seeds = this.state.seeds - seeds.push(item) + seeds.push(uri) this.setState({seeds: seeds}) this.getRecommendations(seeds) } renderSeeds(){ + var seeds_objects = [] + + if (this.state.seeds.length > 0){ + for (var i = 0; i < this.state.seeds.length; i++){ + var uri = this.state.seeds[i] + + switch (helpers.uriType(uri)){ + + case 'track': + if (typeof(this.props.tracks[uri]) !== 'undefined'){ + seeds_objects.push(this.props.tracks[uri]) + } else { + seeds_objects.push({ + name: 'Loading...', + uri: uri + }) + } + break + + case 'artist': + if (typeof(this.props.artists[uri]) !== 'undefined'){ + seeds_objects.push(this.props.artists[uri]) + } else { + seeds_objects.push({ + name: 'Loading...', + uri: uri + }) + } + break + + case 'genre': + var name = helpers.getFromUri('genreid',uri) + seeds_objects.push({ + name: (name.charAt(0).toUpperCase() + name.slice(1)).replace('-',' '), + uri: uri + }) + break + } + } + } + return (
{ - this.state.seeds.map((seed,index) => { + seeds_objects.map((seed,index) => { var type = helpers.uriType(seed.uri) - if (!type){ - type = 'genre' - } return ( {seed.name} ({type}) - this.removeSeed(index)} /> + this.removeSeed(seed.uri)} /> ) }) } - this.handleSelect(e,item)} /> + this.handleSelect(e,uri)} />
) } @@ -180,8 +240,10 @@ class Discover extends React.Component{ const mapStateToProps = (state, ownProps) => { return { - albums: state.ui.albums, - artists: state.ui.artists, + albums: (state.ui.albums ? state.ui.albums : []), + artists: (state.ui.artists ? state.ui.artists : []), + tracks: (state.ui.tracks ? state.ui.tracks : []), + genres: (state.ui.genres ? state.ui.genres : []), authorized: state.spotify.authorized, load_queue: state.ui.load_queue, quick_search_results: (state.spotify.quick_search_results ? state.spotify.quick_search_results : {artists: [], tracks: []}),