Following moved to new component

This commit is contained in:
James Barnsley
2016-11-18 13:21:30 +13:00
parent 89cf46d47b
commit 7389cf7fe9
7 changed files with 151 additions and 136 deletions

View File

@ -0,0 +1,56 @@
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { Link } from 'react-router'
import { createStore, bindActionCreators } from 'redux'
import FontAwesome from 'react-fontawesome'
import * as helpers from '../helpers'
import * as spotifyActions from '../services/spotify/actions'
class FollowButton extends React.Component{
constructor(props) {
super(props);
}
componentDidMount(){
this.props.spotifyActions.following(this.props.uri)
}
remove(){
this.props.spotifyActions.following(this.props.uri, 'DELETE')
}
add(){
this.props.spotifyActions.following(this.props.uri, 'PUT')
}
render(){
if( !this.props.spotify_authorized || !this.props.uri ) return false
var item = this.props[helpers.uriType( this.props.uri )]
if( item.following === true ){
return <button className="tertiary large" onClick={ () => this.remove() }>{ this.props.removeText }</button>
}else{
return <button className="tertiary large" onClick={ () => this.add() }>{ this.props.addText }</button>
}
}
}
const mapStateToProps = (state, ownProps) => {
return {
spotify_authorized: state.spotify.authorized,
artist: state.ui.artist,
album: state.ui.album,
playlist: state.ui.playlist
}
}
const mapDispatchToProps = (dispatch) => {
return {
spotifyActions: bindActionCreators(spotifyActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(FollowButton)

View File

@ -15,6 +15,7 @@ const localstorageMiddleware = (function(){
var actions_to_log = null
//actions_to_log = 'SPOTIFY'
//actions_to_log = 'MOPIDY'
actions_to_log = 'ALBUM_'
if( action.type.startsWith(actions_to_log) ) console.log(action)
switch( action.type ){

View File

@ -357,6 +357,53 @@ export function getSearchResults( query, type = 'album,artist,playlist,track', l
}
}
export function following(uri, method = 'GET'){
return (dispatch, getState) => {
dispatch({ type: 'FOLLOWING_LOADING' });
if( method == 'PUT' ) var is_following = true
if( method == 'DELETE' ) var is_following = false
var asset_name = helpers.uriType(uri);
var endpoint, data
switch( asset_name ){
case 'album':
if( method == 'GET'){
endpoint = 'me/albums/contains/?ids='+ helpers.getFromUri('albumid', uri)
}else{
endpoint = 'me/albums/?ids='+ helpers.getFromUri('albumid', uri)
}
break
case 'artist':
if( method == 'GET' ){
endpoint = 'me/following/contains?type=artist&ids='+ helpers.getFromUri('artistid', uri)
}else{
endpoint = 'me/following?type=artist&ids='+ helpers.getFromUri('artistid', uri)
data = {}
}
break
case 'playlist':
if( method == 'GET' ){
endpoint = 'users/'+ helpers.getFromUri('userid',uri) +'/playlists/'+ helpers.getFromUri('playlistid',uri) +'/followers/contains?ids='+ getState().spotify.me.id
}else{
endpoint = 'users/'+ helpers.getFromUri('userid',uri) +'/playlists/'+ helpers.getFromUri('playlistid',uri) +'/followers'
}
break
}
sendRequest( dispatch, getState, endpoint, method, data )
.then( response => {
if( response ) is_following = response
if( typeof(is_following) === 'object' ) is_following = is_following[0]
dispatch({
type: asset_name.toUpperCase()+'_FOLLOWING_LOADED',
is_following: is_following
});
});
}
}
/**
* =============================================================== ARTIST(S) ============
@ -397,13 +444,6 @@ export function getArtist( uri ){
sendRequest( dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/albums' )
.then( response => {
Object.assign(artist, { albums: response.items, albums_more: response.next });
}),
sendRequest( dispatch, getState, 'me/following/contains?type=artist&ids='+ helpers.getFromUri('artistid', uri) )
.then( response => {
var is_following = 0
if( response.length > 0 ) is_following = response[0]
Object.assign(artist, { following: response[0] } );
})
).then( () => {
@ -454,22 +494,6 @@ export function getLibraryArtists(){
}
}
export function toggleArtistInLibrary( uri, method ){
if( method == 'PUT' ) var new_state = 1
if( method == 'DELETE' ) var new_state = 0
return (dispatch, getState) => {
sendRequest( dispatch, getState, 'me/following?type=artist&ids='+ helpers.getFromUri('artistid',uri), method, {} )
.then( response => {
dispatch({
type: 'SPOTIFY_ARTIST_FOLLOWING',
uri: uri,
data: new_state
});
});
}
}
/**
@ -488,46 +512,30 @@ export function getAlbum( uri ){
// flush out the previous store value
dispatch({ type: 'SPOTIFY_ALBUM_LOADED', data: false });
var album = {}
// get the album
sendRequest( dispatch, getState, 'albums/'+ helpers.getFromUri('albumid', uri) )
.then( response => {
$.when(
var album = response
// get the album
sendRequest( dispatch, getState, 'albums/'+ helpers.getFromUri('albumid', uri) )
.then( response => {
// now get all the artists for this album (full objects)
// we do this to get the artist artwork
var artist_ids = [];
for( var i = 0; i < album.artists.length; i++ ){
artist_ids.push( helpers.getFromUri( 'artistid', album.artists[i].uri ) )
}
Object.assign(album, response)
// now get all the artists for this album (full objects)
// we do this to get the artist artwork
var artist_ids = [];
for( var i = 0; i < album.artists.length; i++ ){
artist_ids.push( helpers.getFromUri( 'artistid', album.artists[i].uri ) )
}
// get all album artists
sendRequest( dispatch, getState, 'artists/?ids='+artist_ids )
.then( response => {
var artists = response.artists
Object.assign(album, {artists: artists})
// get all album artists
sendRequest( dispatch, getState, 'artists/?ids='+artist_ids )
.then( response => {
Object.assign(album, { artists: response.artists })
dispatch({
type: 'SPOTIFY_ALBUM_LOADED',
data: album
});
});
}),
// TODO: Check if we're authenticated before sending this request, otherwise we get a 403
sendRequest( dispatch, getState, 'me/albums/contains?ids='+ helpers.getFromUri('albumid', uri) )
.then( response => {
var is_following = 0
if( response.length > 0 ) is_following = response[0]
Object.assign(album, { following: response[0] } );
})
).then( () => {
dispatch({
type: 'SPOTIFY_ALBUM_LOADED',
data: album
});
});
})
}
}
@ -603,30 +611,14 @@ export function getPlaylist( uri ){
// flush out the previous store value
dispatch({ type: 'SPOTIFY_PLAYLIST_LOADED', data: false });
var playlist = {};
$.when(
// get the main playlist object
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) +'/playlists/'+ helpers.getFromUri('playlistid',uri) +'?market='+getState().spotify.country )
.then( response => {
Object.assign( playlist, response );
}),
// TODO: Check if we're authenticated before sending this request, otherwise we get a 403
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) + '/playlists/'+ helpers.getFromUri('playlistid',uri) + '/followers/contains?ids='+getState().spotify.me.id )
.then( response => {
var is_following = 0
if( response.length > 0 ) is_following = response[0]
Object.assign(playlist, { following: response[0] } );
})
).then( () => {
// get the main playlist object
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) +'/playlists/'+ helpers.getFromUri('playlistid',uri) +'?market='+getState().spotify.country )
.then( response => {
dispatch({
type: 'SPOTIFY_PLAYLIST_LOADED',
data: playlist
});
});
data: response
})
})
}
}

View File

@ -101,6 +101,10 @@ export default function reducer(ui = {}, action){
current_track: current_track
});
case 'FOLLOWING_LOADING':
return Object.assign({}, ui, { following_loading: true })
/**
@ -134,9 +138,9 @@ export default function reducer(ui = {}, action){
})
return Object.assign({}, ui, { album: album });
case 'SPOTIFY_ALBUM_FOLLOWING':
var album = Object.assign({}, ui.album, { following: action.data })
return Object.assign({}, ui, { album: album });
case 'ALBUM_FOLLOWING_LOADED':
var album = Object.assign({}, ui.album, { following: action.is_following })
return Object.assign({}, ui, { album: album, following_loading: false });
@ -165,9 +169,9 @@ export default function reducer(ui = {}, action){
})
return Object.assign({}, ui, { artist: artist });
case 'SPOTIFY_ARTIST_FOLLOWING':
var artist = Object.assign({}, ui.artist, { following: action.data })
return Object.assign({}, ui, { artist: artist });
case 'ARTIST_FOLLOWING_LOADED':
var artist = Object.assign({}, ui.artist, { following: action.is_following })
return Object.assign({}, ui, { artist: artist, following_loading: false });
/**
@ -223,10 +227,6 @@ export default function reducer(ui = {}, action){
})
return Object.assign({}, ui, { playlist: playlist });
case 'SPOTIFY_PLAYLIST_FOLLOWING':
var playlist = Object.assign({}, ui.playlist, { following: action.data })
return Object.assign({}, ui, { playlist: playlist });
case 'PLAYLIST_TRACKS_REMOVED':
var tracks = Object.assign([], ui.playlist.tracks)
var indexes = action.tracks_indexes.reverse()
@ -262,6 +262,10 @@ export default function reducer(ui = {}, action){
var playlist = Object.assign({}, ui.playlist, { snapshot_id: snapshot_id, tracks: tracks })
return Object.assign({}, ui, { playlist: playlist });
case 'PLAYLIST_FOLLOWING_LOADED':
var playlist = Object.assign({}, ui.playlist, { following: action.is_following })
return Object.assign({}, ui, { playlist: playlist, following_loading: false });
/**
* Library Playlists
**/

View File

@ -10,6 +10,7 @@ import Thumbnail from '../components/Thumbnail'
import Parallax from '../components/Parallax'
import ArtistSentence from '../components/ArtistSentence'
import ArtistGrid from '../components/ArtistGrid'
import FollowButton from '../components/FollowButton'
import Dater from '../components/Dater'
import LazyLoadListener from '../components/LazyLoadListener'
@ -63,26 +64,6 @@ class Album extends React.Component{
this.props.mopidyActions.playURIs( tracks_uris )
}
follow(){
this.props.spotifyActions.toggleAlbumInLibrary( this.props.params.uri, 'PUT' )
}
// TODO: Once unfollowing occurs, remove playlist from global playlists list
unfollow(){
this.props.spotifyActions.toggleAlbumInLibrary( this.props.params.uri, 'DELETE' )
}
renderExtraButtons(){
switch( helpers.uriSource( this.props.params.uri ) ){
case 'spotify':
if( !this.props.spotify_authorized ) return null
if( this.props.album.following ){
return <button className="large tertiary" onClick={ e => this.unfollow() }>Remove from library</button>
}
return <button className="large tertiary" onClick={ e => this.follow() }>Add to library</button>
}
}
render(){
if( !this.props.album ) return null
@ -94,7 +75,7 @@ class Album extends React.Component{
<div className="actions">
<button className="large primary" onClick={ e => this.play() }>Play</button>
{ this.renderExtraButtons() }
<FollowButton uri={this.props.params.uri} addText="Add to library" removeText="Remove from library" />
</div>
<ul className="details">

View File

@ -3,7 +3,6 @@ import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import FontAwesome from 'react-fontawesome'
let helpers = require('../helpers.js')
import LazyLoadListener from '../components/LazyLoadListener'
import Header from '../components/Header'
@ -12,7 +11,9 @@ import AlbumGrid from '../components/AlbumGrid'
import Thumbnail from '../components/Thumbnail'
import Parallax from '../components/Parallax'
import ArtistList from '../components/ArtistList'
import FollowButton from '../components/FollowButton'
import * as helpers from '../helpers'
import * as mopidyActions from '../services/mopidy/actions'
import * as lastfmActions from '../services/lastfm/actions'
import * as spotifyActions from '../services/spotify/actions'
@ -55,25 +56,6 @@ class Artist extends React.Component{
alert('Yet to be implemented')
}
follow(){
this.props.spotifyActions.toggleArtistInLibrary( this.props.params.uri, 'PUT' )
}
unfollow(){
this.props.spotifyActions.toggleArtistInLibrary( this.props.params.uri, 'DELETE' )
}
renderExtraButtons(){
switch( helpers.uriSource( this.props.params.uri ) ){
case 'spotify':
if( !this.props.spotify_authorized ) return null
if( this.props.artist.following ){
return <button className="large tertiary" onClick={ e => this.unfollow() }>Unfollow</button>
}
return <button className="large tertiary" onClick={ e => this.follow() }>Follow</button>
}
}
render(){
if( !this.props.artist ) return null
var scheme = helpers.uriSource( this.props.params.uri );
@ -90,7 +72,7 @@ class Artist extends React.Component{
<div className="actions">
<button className="large primary" onClick={ e => this.play() }>Start radio</button>
{ this.renderExtraButtons() }
<FollowButton uri={this.props.params.uri} removeText="Unfollow" addText="Follow" />
</div>
<ul className="details">

View File

@ -4,14 +4,15 @@ import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { Link } from 'react-router'
import FontAwesome from 'react-fontawesome'
import * as helpers from '../helpers'
import TrackList from '../components/TrackList'
import Thumbnail from '../components/Thumbnail'
import Dater from '../components/Dater'
import ConfirmationButton from '../components/ConfirmationButton'
import LazyLoadListener from '../components/LazyLoadListener'
import FollowButton from '../components/FollowButton'
import * as helpers from '../helpers'
import * as uiActions from '../services/ui/actions'
import * as mopidyActions from '../services/mopidy/actions'
import * as spotifyActions from '../services/spotify/actions'
@ -101,10 +102,8 @@ class Playlist extends React.Component{
<ConfirmationButton className="large tertiary" content="Delete" confirmingContent="Are you sure?" onConfirm={ e => this.unfollow() } />
</span>
)
}else if( this.props.playlist.following ){
return <button className="large tertiary" onClick={ e => this.unfollow() }>Unfollow</button>
}
return <button className="large tertiary" onClick={ e => this.follow() }>Follow</button>
return <FollowButton uri={this.props.params.uri} addText="Add to library" removeText="Remove from library" />
}
}