2016-10-20 21:38:01 +13:00
import React , { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
2016-11-14 18:15:22 +13:00
import { Link } from 'react-router'
2016-11-02 16:51:00 +13:00
import FontAwesome from 'react-fontawesome'
2017-01-04 15:24:13 +13:00
import ReactGA from 'react-ga'
2016-10-20 21:38:01 +13:00
import TrackList from '../components/TrackList'
2016-10-31 16:49:42 +13:00
import Thumbnail from '../components/Thumbnail'
import Dater from '../components/Dater'
2016-11-11 09:33:35 +13:00
import ConfirmationButton from '../components/ConfirmationButton'
2016-11-07 18:09:42 +13:00
import LazyLoadListener from '../components/LazyLoadListener'
2016-11-18 13:21:30 +13:00
import FollowButton from '../components/FollowButton'
2016-11-24 08:11:41 +13:00
import SidebarToggleButton from '../components/SidebarToggleButton'
2016-10-23 23:48:06 +13:00
2016-11-18 13:21:30 +13:00
import * as helpers from '../helpers'
2016-11-11 12:12:50 +13:00
import * as uiActions from '../services/ui/actions'
2016-10-21 09:56:07 +13:00
import * as mopidyActions from '../services/mopidy/actions'
2016-11-11 12:12:50 +13:00
import * as spotifyActions from '../services/spotify/actions'
2016-10-20 21:38:01 +13:00
2016-10-21 09:56:07 +13:00
class Playlist extends React . Component {
2016-10-20 21:38:01 +13:00
constructor ( props ) {
super ( props ) ;
}
componentDidMount ( ) {
2016-11-01 11:49:04 +13:00
this . loadPlaylist ( ) ;
2016-10-21 09:56:07 +13:00
}
componentWillReceiveProps ( nextProps ) {
if ( nextProps . params . uri != this . props . params . uri ) {
2016-11-01 11:49:04 +13:00
this . loadPlaylist ( nextProps )
2016-11-09 21:13:40 +13:00
} else if ( ! this . props . mopidy _connected && nextProps . mopidy _connected ) {
2016-11-01 11:49:04 +13:00
if ( helpers . uriSource ( this . props . params . uri ) == 'm3u' ) {
this . loadPlaylist ( nextProps )
}
2016-10-21 09:56:07 +13:00
}
2016-10-20 21:38:01 +13:00
}
2016-11-01 11:49:04 +13:00
loadPlaylist ( props = this . props ) {
2016-11-11 12:12:50 +13:00
switch ( helpers . uriSource ( props . params . uri ) ) {
case 'spotify' :
this . props . spotifyActions . getPlaylist ( props . params . uri ) ;
break
case 'm3u' :
if ( props . mopidy _connected ) this . props . mopidyActions . getPlaylist ( props . params . uri ) ;
break
2016-11-01 11:49:04 +13:00
}
}
2016-11-07 18:09:42 +13:00
loadMore ( ) {
2017-01-13 13:17:47 +13:00
this . props . spotifyActions . getURL ( this . props . playlist . tracks _more , 'PLAYLIST_LOADED_MORE_TRACKS' , this . props . playlist . uri ) ;
2016-11-07 18:09:42 +13:00
}
2016-11-11 09:33:35 +13:00
play ( ) {
2017-01-04 15:24:13 +13:00
ReactGA . event ( { category : 'Playlist' , action : 'Play' , label : this . props . playlist . uri } )
2016-12-06 16:54:48 +13:00
this . props . mopidyActions . playURIs ( [ this . props . playlist . uri ] )
2016-11-11 09:33:35 +13:00
}
follow ( ) {
2017-01-04 15:24:13 +13:00
ReactGA . event ( { category : 'Playlist' , action : 'Follow' , label : this . props . playlist . uri } )
2016-12-06 16:54:48 +13:00
this . props . spotifyActions . toggleFollowingPlaylist ( this . props . playlist . uri , 'PUT' )
2016-11-11 09:33:35 +13:00
}
2016-11-14 21:02:46 +13:00
// TODO: Once unfollowing occurs, remove playlist from global playlists list
2016-11-11 09:33:35 +13:00
unfollow ( ) {
2017-01-04 15:24:13 +13:00
ReactGA . event ( { category : 'Playlist' , action : 'Unfollow' , label : this . props . playlist . uri } )
2016-12-06 16:54:48 +13:00
this . props . spotifyActions . toggleFollowingPlaylist ( this . props . playlist . uri , 'DELETE' )
2016-11-11 09:33:35 +13:00
}
2016-11-14 21:02:46 +13:00
// TODO: Once deletion occurs, remove playlist from global playlists list
2016-11-11 09:33:35 +13:00
delete ( ) {
2017-01-04 15:24:13 +13:00
ReactGA . event ( { category : 'Playlist' , action : 'Delete' , label : this . props . playlist . uri } )
2016-12-06 16:54:48 +13:00
this . props . mopidyActions . deletePlaylist ( this . props . playlist . uri )
2016-11-11 09:33:35 +13:00
}
2016-11-16 13:13:35 +13:00
reorderTracks ( indexes , index ) {
2017-01-04 15:24:13 +13:00
ReactGA . event ( { category : 'Playlist' , action : 'Reorder tracks' , label : this . props . playlist . uri } )
2016-12-14 08:29:24 +13:00
this . props . uiActions . reorderPlaylistTracks ( this . props . playlist . uri , indexes , index , this . props . playlist . snapshot _id )
2016-11-16 13:13:35 +13:00
}
removeTracks ( tracks _indexes ) {
2017-01-04 15:24:13 +13:00
ReactGA . event ( { category : 'Playlist' , action : 'Remove tracks' , label : this . props . playlist . uri } )
2016-11-16 13:13:35 +13:00
this . props . uiActions . removeTracksFromPlaylist ( this . props . playlist . uri , tracks _indexes )
2016-11-11 12:12:50 +13:00
}
2017-02-08 11:12:53 +13:00
renderActions ( ) {
2016-12-06 16:54:48 +13:00
switch ( helpers . uriSource ( this . props . playlist . uri ) ) {
2016-11-11 09:33:35 +13:00
case 'm3u' :
2016-11-14 17:32:36 +13:00
return (
2017-02-08 11:12:53 +13:00
< div className = "actions" >
2017-02-12 21:11:50 +13:00
< button className = "primary" onClick = { e => this . play ( ) } > Play < / b u t t o n >
< button className = "secondary" onClick = { e => this . props . uiActions . openModal ( 'edit_playlist' , { uri : this . props . playlist . uri , name : this . props . playlist . name } ) } > Edit < / b u t t o n >
< ConfirmationButton className = "destructive" content = "Delete" confirmingContent = "Are you sure?" onConfirm = { e => this . delete ( ) } / >
2017-02-08 11:12:53 +13:00
< / d i v >
2016-11-14 17:32:36 +13:00
)
2016-11-11 09:33:35 +13:00
2016-11-14 11:20:02 +13:00
case 'spotify' :
2017-01-13 13:17:47 +13:00
if ( this . props . playlist . can _edit ) {
2016-11-14 17:32:36 +13:00
return (
2017-02-08 11:12:53 +13:00
< div className = "actions" >
2017-02-12 21:11:50 +13:00
< button className = "primary" onClick = { e => this . play ( ) } > Play < / b u t t o n >
< button className = "secondary" onClick = { e => this . props . uiActions . openModal ( 'edit_playlist' , { uri : this . props . playlist . uri , name : this . props . playlist . name , is _public : this . props . playlist . public } ) } > Edit < / b u t t o n >
< ConfirmationButton className = "destructive" content = "Delete" confirmingContent = "Are you sure?" onConfirm = { e => this . unfollow ( ) } / >
2017-02-08 11:12:53 +13:00
< / d i v >
2016-11-14 17:32:36 +13:00
)
2016-11-11 09:33:35 +13:00
}
2017-02-08 11:12:53 +13:00
return (
< div className = "actions" >
2017-02-12 21:11:50 +13:00
< button className = "primary" onClick = { e => this . play ( ) } > Play < / b u t t o n >
2017-02-12 21:36:45 +13:00
< FollowButton className = "secondary" uri = { this . props . playlist . uri } addText = "Add to library" removeText = "Remove from library" is _following = { this . props . playlist . is _following } / >
2017-02-08 11:12:53 +13:00
< / d i v >
)
2016-11-11 09:33:35 +13:00
2017-02-08 11:12:53 +13:00
default :
return (
< div className = "actions" >
2017-02-12 21:36:45 +13:00
< button className = "primary" onClick = { e => this . play ( ) } > Play < / b u t t o n >
2017-02-08 11:12:53 +13:00
< / d i v >
)
2016-11-11 09:33:35 +13:00
}
}
2016-11-01 13:19:51 +13:00
render ( ) {
2017-01-29 16:25:05 +13:00
if ( ! this . props . playlist || ! this . props . playlist . name ) return null
var scheme = helpers . uriSource ( this . props . playlist . uri )
var context = 'playlist-track'
if ( this . props . playlist . can _edit ) context = 'editable-playlist-track'
2016-11-01 13:19:51 +13:00
return (
< div className = "view playlist-view" >
2016-11-24 08:11:41 +13:00
< SidebarToggleButton / >
2017-02-07 20:07:04 +13:00
< Thumbnail size = "large" canZoom images = { this . props . playlist . images } / >
2016-11-11 09:33:35 +13:00
2017-02-07 20:07:04 +13:00
< div className = "title" >
< div className = "source grey-text" >
< FontAwesome name = { helpers . sourceIcon ( this . props . params . uri ) } / > { helpers . uriSource ( this . props . params . uri ) } playlist
2016-11-11 09:33:35 +13:00
< / d i v >
2017-02-07 20:07:04 +13:00
< h1 > { this . props . playlist . name } < / h 1 >
{ this . props . playlist . description ? < div className = "description grey-text" dangerouslySetInnerHTML = { { _ _html : this . props . playlist . description } } > < / d i v > : n u l l }
2016-11-11 09:33:35 +13:00
2016-11-02 16:51:00 +13:00
< ul className = "details" >
2017-02-07 20:07:04 +13:00
{ this . props . playlist . owner ? < li > < Link to = { '/user/' + this . props . playlist . owner . uri } > { this . props . playlist . owner . id } < / L i n k > < / l i > : n u l l }
{ this . props . playlist . followers ? < li > { this . props . playlist . followers . total . toLocaleString ( ) } followers < / l i > : n u l l }
{ this . props . playlist . last _modified ? < li > < Dater type = "ago" data = { this . props . playlist . last _modified } / > < / l i > : n u l l }
2016-11-28 07:27:30 +13:00
< li >
2017-02-07 20:07:04 +13:00
{ this . props . playlist . tracks _total ? this . props . playlist . tracks _total : '0' } tracks , & nbsp ;
{ this . props . playlist . tracks ? < Dater type = "total-time" data = { this . props . playlist . tracks } / > : '0 mins' }
2016-11-28 07:27:30 +13:00
< / l i >
2016-11-02 16:51:00 +13:00
< / u l >
2016-10-20 21:38:01 +13:00
< / d i v >
2016-11-07 21:21:15 +13:00
2017-02-08 11:12:53 +13:00
{ this . renderActions ( ) }
2017-02-07 20:07:04 +13:00
< section className = "list-wrapper" >
2017-02-14 12:13:07 +13:00
{ this . props . playlist . tracks ? < TrackList uri = { this . props . params . uri } context = { context } tracks = { this . props . playlist . tracks } removeTracks = { tracks _indexes => this . removeTracks ( tracks _indexes ) } reorderTracks = { ( indexes , index ) => this . reorderTracks ( indexes , index ) } / > : null }
2017-02-07 20:07:04 +13:00
< LazyLoadListener enabled = { this . props . playlist . tracks _more } loadMore = { ( ) => this . loadMore ( ) } / >
< / s e c t i o n >
2016-11-01 13:19:51 +13:00
< / d i v >
)
2016-10-20 21:38:01 +13:00
}
}
/ * *
* Export our component
*
* We also integrate our global store , using connect ( )
* * /
const mapStateToProps = ( state , ownProps ) => {
2017-02-03 09:04:47 +13:00
var uri = ownProps . params . uri
uri = uri . replace ( ' ' , '%20' )
2016-11-09 21:13:40 +13:00
return {
2017-02-03 09:04:47 +13:00
playlist : ( state . ui . playlists && typeof ( state . ui . playlists [ uri ] ) !== 'undefined' ? state . ui . playlists [ uri ] : false ) ,
2016-11-11 09:33:35 +13:00
mopidy _connected : state . mopidy . connected ,
spotify _authorized : state . spotify . authorized ,
spotify _userid : state . spotify . me . id
2016-11-09 21:13:40 +13:00
}
2016-10-20 21:38:01 +13:00
}
const mapDispatchToProps = ( dispatch ) => {
return {
2016-11-11 12:12:50 +13:00
uiActions : bindActionCreators ( uiActions , dispatch ) ,
2016-10-20 21:38:01 +13:00
mopidyActions : bindActionCreators ( mopidyActions , dispatch ) ,
spotifyActions : bindActionCreators ( spotifyActions , dispatch )
}
}
2016-10-21 09:56:07 +13:00
export default connect ( mapStateToProps , mapDispatchToProps ) ( Playlist )