Merge branch 'master' of github.com:jaedb/Iris

This commit is contained in:
James Barnsley
2017-01-11 18:12:02 +13:00
7 changed files with 165 additions and 11 deletions

33
src/js/components/GridSlider.js Executable file
View File

@ -0,0 +1,33 @@
import React, { PropTypes } from 'react'
import GridItem from './GridItem'
export default class GridSlider extends React.Component{
constructor(props) {
super(props);
}
render(){
if( this.props.tracks ){
var className = "grid-slider"
if( this.props.className ) className += ' '+this.props.className
return (
<div className={className}>
<div className="grid artist-grid liner">
{
this.props.tracks.map(
(track, index) => {
var item = Object.assign({}, track.album, { artists: track.artists })
return <GridItem item={item} key={index} link={global.baseURL+'album/'+track.album.uri} />
}
)
}
</div>
</div>
);
}
return null;
}
}

View File

@ -16,18 +16,24 @@ const sendRequest = ( dispatch, getState, endpoint, method = 'GET', data = false
getToken( dispatch, getState )
.then( response => {
// prepend the API baseurl, unless the endpoint already has it (ie pagination requests)
var url = 'https://api.spotify.com/v1/'+endpoint
if( endpoint.startsWith('https://api.spotify.com/') ) url = endpoint;
$.ajax({
method: method,
cache: true,
url: url,
headers: {
Authorization: 'Bearer '+ response
},
data: JSON.stringify(data)
}).then(
// create our ajax request config
var config = {
method: method,
url: url,
cached: true,
headers: {
Authorization: 'Bearer '+ response
}
}
// 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)
$.ajax(config).then(
response => {
resolve(response)
},
@ -477,6 +483,57 @@ export function resolveRadioSeeds( radio ){
}
/**
* =============================================================== DISCOVER =============
* ======================================================================================
**/
/**
* Get our recommendations
* This is based off our 'favorites' and then we use those as seeds
*
* @param uri string
**/
export function getDiscover(){
return (dispatch, getState) => {
dispatch({ type: 'SPOTIFY_DISCOVER_LOADED', data: false })
// get favorite tracks
sendRequest( dispatch, getState, 'me/top/tracks?limit=50&time_range=long_term' )
.then( response => {
var favorite_tracks_uris = helpers.asURIs(response.items)
favorite_tracks_uris = favorite_tracks_uris.sort(() => .5 - Math.random())
favorite_tracks_uris = favorite_tracks_uris.slice(0,10)
for (var i = 0; i < favorite_tracks_uris.length; i++){
var seed_id = helpers.getFromUri('trackid',favorite_tracks_uris[i] )
$.when(
sendRequest( dispatch, getState, 'recommendations?seed_tracks='+seed_id ),
sendRequest( dispatch, getState, 'tracks/'+seed_id )
).then( ( tracks_response, seed_response ) => {
dispatch({
type: 'SPOTIFY_DISCOVER_LOADED',
data: {
tracks: tracks_response.tracks,
seed: seed_response
}
});
});
}
})
}
}
/**
* =============================================================== ARTIST(S) ============
* ======================================================================================

View File

@ -178,6 +178,10 @@ export default function reducer(spotify = {}, action){
items: [ ...spotify.new_releases.items, ...action.data.albums.items ]
}})
case 'SPOTIFY_DISCOVER_LOADED':
if( !action.data ) return Object.assign({}, spotify, { discover: [] })
return Object.assign({}, spotify, { discover: [...spotify.discover, ...[action.data]] })
default:
return spotify
}

View File

@ -4,6 +4,8 @@ import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import Header from '../../components/Header'
import GridSlider from '../../components/GridSlider'
import ArtistSentence from '../../components/ArtistSentence'
import * as helpers from '../../helpers'
import * as spotifyActions from '../../services/spotify/actions'
@ -14,11 +16,36 @@ class Discover extends React.Component{
super(props);
}
componentDidMount(){
this.props.spotifyActions.getDiscover()
}
renderRecommendations(){
if (!this.props.discover || this.props.discover.length <= 0) return null
return (
<section className="recommendations">
{
this.props.discover.map(
(discover, index) => {
return (
<div className="grid-slider-wrapper" key={index}>
<h4>Because you listened to <ArtistSentence artists={discover.seed.artists} /></h4>
<GridSlider tracks={discover.tracks} />
</div>
)
}
)
}
</section>
)
}
render(){
return (
<div className="view discover-view">
<Header icon="compass" title="Discover" />
<h1>To come</h1>
{ this.renderRecommendations() }
</div>
)
}
@ -33,7 +60,8 @@ class Discover extends React.Component{
const mapStateToProps = (state, ownProps) => {
return {
authorized: state.spotify.authorized,
discover: state.spotify.discover
}
}

View File

@ -18,6 +18,7 @@
@import 'components/sidebar-toggle-button';
@import 'components/lists';
@import 'components/grid';
@import 'components/grid-slider';
@import 'components/header';
@import 'components/notifications';
@import 'components/dropdown-field';
@ -29,5 +30,6 @@
@import 'views/queue';
@import 'views/search';
@import 'views/library';
@import 'views/discover';
@import 'views/settings';

View File

@ -0,0 +1,24 @@
.grid-slider-wrapper {
padding-bottom: 40px;
.grid-slider {
position: relative;
overflow-x: scroll;
overflow-y: hidden;
height: 220px;
.liner {
position: absolute;
top: 0;
left: 0;
width: 400%;
box-sizing: border-box;
.grid-item {
width: 4%;
margin: 0 0.5% !important;
}
}
}
}

6
src/scss/views/_discover.scss Executable file
View File

@ -0,0 +1,6 @@
.discover-view {
section {
padding: 40px;
}
}