diff --git a/src/js/components/AutocompleteField.js b/src/js/components/AutocompleteField.js
index bd58da3e..729b313b 100755
--- a/src/js/components/AutocompleteField.js
+++ b/src/js/components/AutocompleteField.js
@@ -2,6 +2,7 @@
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
+import { Link, hashHistory } from 'react-router'
import ArtistSentence from './ArtistSentence'
import * as helpers from '../helpers'
@@ -11,6 +12,7 @@ class AutocompleteField extends React.Component{
constructor(props) {
super(props)
+
this.state = {
value: ''
}
@@ -21,6 +23,10 @@ class AutocompleteField extends React.Component{
componentDidMount(){
window.addEventListener("click", this.handleClick, false)
+
+ if (this.props.types.includes('genre') && !this.props.genres){
+ this.props.spotifyActions.getGenres()
+ }
}
componentWillUnmount(){
@@ -33,10 +39,20 @@ class AutocompleteField extends React.Component{
}
}
- handleChange(value){
+ handleChange(e,value){
var self = this
- clearTimeout(this.timer)
+
+ // update our local state
this.setState({value: value})
+
+ // pass the change up the line
+ if (this.props.onChange){
+ this.props.onChange(e,value)
+ }
+
+ // start a timer to perform the actual search
+ // this provides a wee delay between key presses to avoid request spamming
+ clearTimeout(this.timer)
this.timer = setTimeout(
function(){
self.setState({searching: true})
@@ -46,14 +62,43 @@ class AutocompleteField extends React.Component{
)
}
- handleSelect(item){
+ handleSelect(e,item){
if (this.props.clearOnSelect){
this.setState({value: ''})
} else {
this.setState({value: item.name})
}
- this.props.handleSelect(item)
+ // if we have a handler to pass down to
+ if (this.props.onSelect){
+ this.props.onSelect(e,item)
+
+ // no handler, so let's just go to this asset
+ } else {
+ switch (helpers.uriType(item.uri)){
+
+ case 'album':
+ hashHistory.push(global.baseURL+'album/'+item.uri)
+ break
+
+ case 'artist':
+ hashHistory.push(global.baseURL+'artist/'+item.uri)
+ break
+
+ case 'playlist':
+ hashHistory.push(global.baseURL+'playlist/'+item.uri)
+ break
+
+ case 'track':
+ hashHistory.push(global.baseURL+'album/'+item.album.uri)
+ break
+
+ case 'search':
+ hashHistory.push(global.baseURL+'search/'+item.uri)
+ break
+ }
+ }
+
this.props.spotifyActions.clearAutocompleteResults(this.id)
}
@@ -67,6 +112,18 @@ class AutocompleteField extends React.Component{
}
}
+ renderAllResultsButton(){
+ if (this.props.hideAllResultsButton || !this.results()){
+ return null
+ } else {
+ return (
+
this.handleSelect(e,{uri:'iris:search:all:'+this.state.value, name: ''})}>
+ All results
+
+ )
+ }
+ }
+
renderResults(type){
var results = this.results()
if (!results || typeof(results[type]) === 'undefined' || results[type].length <= 0) return null
@@ -80,7 +137,7 @@ class AutocompleteField extends React.Component{
{
items.map(item => {
return (
-
@@ -115,6 +172,7 @@ class AutocompleteField extends React.Component{
)
})
}
+ {this.renderAllResultsButton()}
);
@@ -123,6 +181,7 @@ class AutocompleteField extends React.Component{
const mapStateToProps = (state, ownProps) => {
return {
+ genres: (state.spotify.genres ? state.spotify.genres : null),
results: (state.spotify.autocomplete_results ? state.spotify.autocomplete_results : {})
}
}
diff --git a/src/js/components/LazyLoadListener.js b/src/js/components/LazyLoadListener.js
index a9d29778..92020ec2 100755
--- a/src/js/components/LazyLoadListener.js
+++ b/src/js/components/LazyLoadListener.js
@@ -31,8 +31,8 @@ export default class LazyLoadListener extends React.Component{
render(){
return (
-
-
+
+ {this.state.loading ?
: null}
)
}
diff --git a/src/js/components/SearchForm.js b/src/js/components/SearchForm.js
index ffc367f1..facfd73f 100755
--- a/src/js/components/SearchForm.js
+++ b/src/js/components/SearchForm.js
@@ -5,6 +5,7 @@ import { Link, hashHistory } from 'react-router'
import { createStore, bindActionCreators } from 'redux'
import FontAwesome from 'react-fontawesome'
+import AutocompleteField from './AutocompleteField'
import * as helpers from '../helpers'
import * as uiActions from '../services/ui/actions'
@@ -18,7 +19,7 @@ class SearchForm extends React.Component{
}
}
- handleSubmit(e){
+ handleSubmit(e,value){
e.preventDefault()
// check for uri type matching
@@ -46,12 +47,12 @@ class SearchForm extends React.Component{
render(){
return (
-
)
}
diff --git a/src/js/helpers.js b/src/js/helpers.js
index fa771163..8ba2b1d0 100755
--- a/src/js/helpers.js
+++ b/src/js/helpers.js
@@ -442,4 +442,26 @@ export let setWindowTitle = function (track = false, play_state = false){
}
document.title = title
+}
+
+
+/**
+ * Detect if an item is in the loading queue. We simply loop all load items to
+ * see if any items contain our searched key.
+ *
+ * TODO: Explore performance of this
+ *
+ * @param load_queue = obj (passed from store)
+ * @param key = string (the string to lookup)
+ * @return boolean
+ **/
+export let isLoading = function(load_queue = [], key = ''){
+ for (var load_queue_key in load_queue) {
+ if (load_queue.hasOwnProperty(load_queue_key)){
+ if (load_queue[load_queue_key] == key){
+ return true
+ }
+ }
+ }
+ return false
}
\ No newline at end of file
diff --git a/src/js/services/spotify/actions.js b/src/js/services/spotify/actions.js
index c095ff65..6c1685b0 100755
--- a/src/js/services/spotify/actions.js
+++ b/src/js/services/spotify/actions.js
@@ -34,7 +34,13 @@ const sendRequest = ( dispatch, getState, endpoint, method = 'GET', data = false
}
// only if we've got data do we add it to the request (this prevents appending of "&false" to the URL)
- if (data) config.data = JSON.stringify(data)
+ if (data){
+ if (typeof(data) === 'string'){
+ config.data = data
+ } else {
+ config.data = JSON.stringify(data)
+ }
+ }
// add reference to loader queue
var loader_key = helpers.generateGuid()
@@ -461,7 +467,6 @@ export function getSearchResults(query, type = 'album,artist,playlist,track', li
export function getAutocompleteResults(field_id, query, types = ['album','artist','playlist','track']){
return (dispatch, getState) => {
- console.log(types)
dispatch({type: 'SPOTIFY_AUTOCOMPLETE_LOADING', field_id: field_id})
@@ -475,16 +480,14 @@ export function getAutocompleteResults(field_id, query, types = ['album','artist
endpoint += '&type='+types.join(',')
endpoint += '&country='+getState().spotify.country
- $.when(
- sendRequest(dispatch, getState, endpoint),
- sendRequest(dispatch, getState, 'recommendations/available-genre-seeds')
-
- ).then((search_response, genres_response) => {
+ sendRequest(dispatch, getState, endpoint)
+ .then(response => {
var genres = []
if (genre_included){
- for (var i = 0; i < genres_response.genres.length; i++){
- if (genres_response.genres[i].includes(query)){
- var genre = genres_response.genres[i]
+ 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
@@ -496,10 +499,10 @@ export function getAutocompleteResults(field_id, query, types = ['album','artist
type: 'SPOTIFY_AUTOCOMPLETE_LOADED',
field_id: field_id,
results: {
- artists: (search_response.artists ? search_response.artists.items : []),
- albums: (search_response.albums ? search_response.albums.items : []),
- playlists: (search_response.playlists ? search_response.playlists.items : []),
- tracks: (search_response.tracks ? search_response.tracks.items : []),
+ artists: (response.artists ? response.artists.items : []),
+ albums: (response.albums ? response.albums.items : []),
+ playlists: (response.playlists ? response.playlists.items : []),
+ tracks: (response.tracks ? response.tracks.items : []),
genres: genres
}
});
@@ -656,7 +659,7 @@ export function getFavorites(limit = 50, term = 'long_term'){
export function getRecommendations(uris = []){
return (dispatch, getState) => {
- dispatch({ type: 'SPOTIFY_RECOMMENDATIONS_LOADED', data: false })
+ dispatch({type: 'SPOTIFY_RECOMMENDATIONS_LOADED', tracks: []})
// build our starting point
var artists_ids = []
@@ -687,12 +690,11 @@ export function getRecommendations(uris = []){
}
// construct our endpoint URL with all the appropriate arguments
- var endpoint = 'recommendations'
- endpoint += '?seed_artists='+artists_ids.join(',')
- endpoint += '&seed_tracks='+tracks_ids.join(',')
- endpoint += '&seed_genres='+genres.join(',')
+ var data = 'seed_artists='+artists_ids.join(',')
+ data += '&seed_tracks='+tracks_ids.join(',')
+ data += '&seed_genres='+genres.join(',')
- sendRequest(dispatch, getState, endpoint)
+ sendRequest(dispatch, getState, 'recommendations', 'GET', data)
.then( response => {
dispatch({
type: 'SPOTIFY_RECOMMENDATIONS_LOADED',
@@ -714,7 +716,7 @@ export function getGenres(){
.then( response => {
dispatch({
type: 'SPOTIFY_GENRES_LOADED',
- genres: response
+ genres: response.genres
});
})
}
diff --git a/src/js/views/discover/Discover.js b/src/js/views/discover/Discover.js
index c1cca3c1..c4d71870 100755
--- a/src/js/views/discover/Discover.js
+++ b/src/js/views/discover/Discover.js
@@ -22,20 +22,27 @@ class Discover extends React.Component{
this._autocomplete_timer = false
this.state = {
- seeds: [],
+ seeds: [
+ {
+ uri: 'spotify:genre:chill',
+ name: 'Chill'
+ }
+ ],
+ add_seed: '',
adding_seed: false
}
}
componentDidMount(){
- this.props.spotifyActions.getGenres()
if (this.props.authorized){
this.props.spotifyActions.getFavorites()
+ } else {
+ this.getRecommendations()
}
}
componentWillReceiveProps(newProps, newState){
- if (this.props.favorite_artists.length <= 0 && newProps.favorite_artists.length > 0 && this.state.seeds.length <= 0){
+ if (this.props.favorite_artists.length <= 0 && newProps.favorite_artists.length){
var initial_seeds = newProps.favorite_artists.sort(() => .5 - Math.random())
initial_seeds = initial_seeds.slice(0,2)
@@ -56,7 +63,7 @@ class Discover extends React.Component{
this.getRecommendations(seeds)
}
- handleSelect(item){
+ handleSelect(e,item){
var seeds = this.state.seeds
seeds.push(item)
this.setState({seeds: seeds})
@@ -81,7 +88,13 @@ class Discover extends React.Component{
)
})
}
-
this.handleSelect(item)} clearOnSelect />
+ this.handleSelect(e,item)}
+ clearOnSelect
+ hideAllResultsButton />
)
}
@@ -94,11 +107,14 @@ class Discover extends React.Component{