2016-10-17 10:39:11 +13:00
import React , { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
2017-05-05 04:50:22 +12:00
import { Link } from 'react-router'
2016-11-07 21:21:15 +13:00
import FontAwesome from 'react-fontawesome'
2016-10-17 10:39:11 +13:00
2016-11-01 08:57:28 +13:00
import LazyLoadListener from '../components/LazyLoadListener'
2016-10-24 21:26:01 +13:00
import Header from '../components/Header'
2016-10-17 10:39:11 +13:00
import TrackList from '../components/TrackList'
2016-10-18 21:57:29 +13:00
import AlbumGrid from '../components/AlbumGrid'
2016-10-25 17:01:37 +13:00
import Thumbnail from '../components/Thumbnail'
import Parallax from '../components/Parallax'
2016-11-23 13:17:07 +13:00
import ArtistGrid from '../components/ArtistGrid'
2017-03-13 21:19:09 +13:00
import RelatedArtists from '../components/RelatedArtists'
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'
2017-02-28 16:13:27 +13:00
import ContextMenuTrigger from '../components/ContextMenuTrigger'
2016-10-18 21:57:29 +13:00
2016-11-18 13:21:30 +13:00
import * as helpers from '../helpers'
2016-12-20 16:58:20 +13:00
import * as uiActions from '../services/ui/actions'
2016-11-01 16:41:04 +13:00
import * as mopidyActions from '../services/mopidy/actions'
2016-12-20 16:58:20 +13:00
import * as pusherActions from '../services/pusher/actions'
2016-11-07 21:21:15 +13:00
import * as lastfmActions from '../services/lastfm/actions'
2016-10-17 10:39:11 +13:00
import * as spotifyActions from '../services/spotify/actions'
class Artist extends React . Component {
constructor ( props ) {
2016-11-23 13:17:07 +13:00
super ( props )
2016-10-17 10:39:11 +13:00
}
componentDidMount ( ) {
2017-07-17 04:19:02 +12:00
this . loadArtist ( )
2016-10-17 10:39:11 +13:00
}
componentWillReceiveProps ( nextProps ) {
if ( nextProps . params . uri != this . props . params . uri ) {
2016-11-01 16:41:04 +13:00
this . loadArtist ( nextProps )
2016-11-09 21:13:40 +13:00
} else if ( ! this . props . mopidy _connected && nextProps . mopidy _connected ) {
2017-02-26 18:33:20 +13:00
if ( helpers . uriSource ( this . props . params . uri ) != 'spotify' ) {
2016-11-01 16:41:04 +13:00
this . loadArtist ( nextProps )
}
}
}
2017-02-27 08:44:02 +13:00
handleContextMenu ( e ) {
var data = {
e : e ,
context : 'artist' ,
2017-02-28 16:13:27 +13:00
items : [ this . props . artist ] ,
2017-02-27 08:44:02 +13:00
uris : [ this . props . params . uri ]
}
this . props . uiActions . showContextMenu ( data )
}
2016-11-01 16:41:04 +13:00
loadArtist ( props = this . props ) {
2017-01-15 11:40:08 +13:00
switch ( helpers . uriSource ( props . params . uri ) ) {
case 'spotify' :
if ( props . artist && props . artist . albums _uris && props . artist . related _artists _uris ) {
console . info ( 'Loading spotify artist from index' )
} else {
2017-06-02 16:16:48 +12:00
this . props . spotifyActions . getArtist ( props . params . uri , true ) ;
2017-01-15 11:40:08 +13:00
}
break
2017-02-23 22:06:43 +13:00
default :
2017-01-15 21:06:24 +13:00
if ( props . mopidy _connected ) {
if ( props . artist && props . artist . images ) {
console . info ( 'Loading local artist from index' )
} else {
2017-06-02 16:16:48 +12:00
this . props . mopidyActions . getArtist ( props . params . uri ) ;
2017-01-15 21:06:24 +13:00
}
}
2017-01-15 11:40:08 +13:00
break
2016-10-17 10:39:11 +13:00
}
}
2016-11-01 08:57:28 +13:00
loadMore ( ) {
2017-01-15 11:40:08 +13:00
this . props . spotifyActions . getURL ( this . props . artist . albums _more , 'SPOTIFY_ARTIST_ALBUMS_LOADED' , this . props . params . uri ) ;
2016-11-01 08:57:28 +13:00
}
2017-03-09 21:37:16 +13:00
inLibrary ( ) {
return ( this . props . library _artists && this . props . library _artists . indexOf ( this . props . params . uri ) > - 1 )
}
2016-11-23 13:17:07 +13:00
renderSubViewMenu ( ) {
2016-11-01 16:41:04 +13:00
return (
2016-11-23 13:17:07 +13:00
< div className = "sub-views" >
2017-07-25 16:33:31 +12:00
< Link className = "option" activeClassName = "active" to = { global . baseURL + 'artist/' + this . props . params . uri } > < h4 > Overview < / h 4 > < / L i n k >
< Link className = "option" activeClassName = "active" to = { global . baseURL + 'artist/' + this . props . params . uri + '/related-artists' } > < h4 > Related artists < / h 4 > < / L i n k >
< Link className = "option" activeClassName = "active" to = { global . baseURL + 'artist/' + this . props . params . uri + '/about' } > < h4 > About < / h 4 > < / L i n k >
2016-11-23 13:17:07 +13:00
< / d i v >
)
}
2016-11-18 10:02:05 +13:00
2016-11-23 13:17:07 +13:00
renderBody ( ) {
2017-05-22 04:19:44 +12:00
if ( helpers . isLoading ( this . props . load _queue , [ 'spotify_artists/' + helpers . getFromUri ( 'artistid' , this . props . params . uri ) , 'lastfm_method=artist.getInfo' ] ) ) {
return (
< div className = "body-loader" >
< div className = "loader" > < / d i v >
< / d i v >
)
}
2017-02-07 10:00:29 +13:00
var scheme = helpers . uriSource ( this . props . params . uri ) ;
2017-01-14 10:03:45 +13:00
var related _artists = [ ]
2017-01-15 11:40:08 +13:00
if ( this . props . artist . related _artists _uris ) {
for ( var i = 0 ; i < this . props . artist . related _artists _uris . length ; i ++ ) {
var uri = this . props . artist . related _artists _uris [ i ]
2017-01-14 10:03:45 +13:00
if ( this . props . artists . hasOwnProperty ( uri ) ) {
related _artists . push ( this . props . artists [ uri ] )
}
}
}
var albums = [ ]
2017-01-15 11:40:08 +13:00
if ( this . props . artist . albums _uris ) {
for ( var i = 0 ; i < this . props . artist . albums _uris . length ; i ++ ) {
var uri = this . props . artist . albums _uris [ i ]
2017-01-14 10:03:45 +13:00
if ( this . props . albums . hasOwnProperty ( uri ) ) {
albums . push ( this . props . albums [ uri ] )
}
}
}
2017-05-05 04:50:22 +12:00
switch ( this . props . params . sub _view ) {
2017-02-08 19:31:36 +13:00
2017-05-05 04:50:22 +12:00
case 'related-artists' :
return (
< div className = "body related-artists" >
< section className = "grid-wrapper no-top-padding" >
< ArtistGrid artists = { related _artists } / >
2017-02-08 19:31:36 +13:00
< / s e c t i o n >
< / d i v >
2017-05-05 04:50:22 +12:00
)
case 'about' :
return (
< div className = "body about" >
2017-08-03 21:26:33 +12:00
< div className = "col w40 tiles artist-stats" >
2017-07-24 17:57:44 +12:00
{ this . props . artist . images ? < div className = "tile thumbnail-wrapper" > < Thumbnail size = "huge" canZoom images = { this . props . artist . images } / > < / d i v > : n u l l }
2017-05-05 04:50:22 +12:00
{ this . props . artist . images _additional ? < div className = "tile thumbnail-wrapper" > < Thumbnail size = "huge" canZoom images = { this . props . artist . images _additional } / > < / d i v > : n u l l }
2017-08-03 21:26:33 +12:00
{ this . props . artist . followers ? < div className = "tile" > < span className = "content" > < FontAwesome name = "users" / > { this . props . artist . followers . total . toLocaleString ( ) } followers < / s p a n > < / d i v > : n u l l }
{ this . props . artist . popularity ? < div className = "tile" > < span className = "content" > < FontAwesome name = "fire" / > { this . props . artist . popularity } % popularity < / s p a n > < / d i v > : n u l l }
{ this . props . artist . listeners ? < div className = "tile" > < span className = "content" > < FontAwesome name = "headphones" / > { this . props . artist . listeners . toLocaleString ( ) } listeners < / s p a n > < / d i v > : n u l l }
2017-05-05 04:50:22 +12:00
< / d i v >
< div className = "col w60 biography" >
< section >
{ this . props . artist . bio ? < div className = "biography-text" > < p > { this . props . artist . bio . content } < /p><br / >
< div className = "grey-text" > Published : { this . props . artist . bio . published } < / d i v >
< div className = "grey-text" > Origin : < a href = { this . props . artist . bio . links . link . href } target = "_blank" > { this . props . artist . bio . links . link . href } < / a > < / d i v > < / d i v > : n u l l }
< / s e c t i o n >
< / d i v >
2017-02-10 22:22:33 +13:00
< / d i v >
2017-05-05 04:50:22 +12:00
)
2016-11-01 16:41:04 +13:00
2017-05-05 04:50:22 +12:00
default :
return (
< div className = "body overview" >
< div className = { related _artists . length > 0 ? "col w70" : "col w100" } >
2017-06-18 05:47:36 +12:00
< h4 > Top tracks < / h 4 >
2017-05-05 04:50:22 +12:00
< div className = "list-wrapper" >
{ this . props . artist . tracks ? < TrackList className = "artist-track-list" uri = { this . props . params . uri } tracks = { this . props . artist . tracks } / > : null }
< / d i v >
< / d i v >
2016-11-01 16:41:04 +13:00
2017-05-05 04:50:22 +12:00
< div className = "col w5" > < / d i v >
2016-11-01 16:41:04 +13:00
2017-06-19 07:38:23 +12:00
{ related _artists . length > 0 ? < div className = "col w25 related-artists" > < h4 > Related artists < /h4><div className="list-wrapper"><RelatedArtists artists={related_artists.slice(0,6)} / > < /div><Link to={global.baseURL+'artist/ '+this.props.params.uri+' / related - artists ' } className = "button" > All related artists < / L i n k > < / d i v > : n u l l }
2016-11-01 16:41:04 +13:00
2017-05-05 04:50:22 +12:00
< div className = "cf" > < / d i v >
2017-06-18 05:47:36 +12:00
< h4 > Albums < / h 4 >
2017-05-05 04:50:22 +12:00
< section className = "grid-wrapper no-top-padding" >
< AlbumGrid albums = { albums } / >
< LazyLoadListener enabled = { this . props . artist . albums _more } loadMore = { ( ) => this . loadMore ( ) } / >
< / s e c t i o n >
< / d i v >
)
}
2016-11-23 13:17:07 +13:00
}
render ( ) {
2017-05-22 04:19:44 +12:00
var scheme = helpers . uriSource ( this . props . params . uri )
2016-11-23 13:17:07 +13:00
2017-02-23 22:06:43 +13:00
if ( this . props . artist && this . props . artist . images ) {
var image = helpers . sizedImages ( this . props . artist . images ) . huge
} else {
var image = null
}
2016-11-23 18:19:51 +13:00
2017-02-23 22:06:43 +13:00
if ( this . props . artist ) {
2017-02-27 07:31:58 +13:00
var can _play _radio = ( scheme == 'spotify' )
var can _follow = ( scheme == 'spotify' )
2017-02-23 22:06:43 +13:00
return (
< div className = "view artist-view" >
2016-11-23 13:17:07 +13:00
2017-07-17 07:16:33 +12:00
{ this . props . slim _mode ? < Header className = "overlay" icon = "mic" title = "Artist" handleContextMenuTrigger = { e => this . handleContextMenu ( e ) } uiActions = { this . props . uiActions } / > : null }
2016-11-24 08:11:41 +13:00
2017-02-23 22:06:43 +13:00
< div className = "intro" >
2016-11-23 13:17:07 +13:00
2017-07-24 06:03:09 +12:00
< Parallax image = { image } / >
2016-11-23 13:17:07 +13:00
2017-02-23 22:06:43 +13:00
< div className = "liner" >
< h1 > { this . props . artist ? this . props . artist . name : null } < / h 1 >
2017-02-27 07:31:58 +13:00
< div className = "actions" >
2017-03-30 18:40:45 +13:00
{ can _play _radio ? < button className = "primary" onClick = { e => this . props . pusherActions . startRadio ( [ this . props . artist . uri ] ) } > Start radio < / b u t t o n > : < b u t t o n c l a s s N a m e = " p r i m a r y " o n C l i c k = { e = > t h i s . p r o p s . m o p i d y A c t i o n s . p l a y U R I s ( t h i s . p r o p s . a r t i s t . a l b u m s _ u r i s , t h i s . p r o p s . a r t i s t . u r i ) } > P l a y a l l < / b u t t o n > }
2017-03-10 22:35:11 +13:00
{ can _follow ? < FollowButton className = "white" uri = { this . props . params . uri } removeText = "Remove from library" addText = "Add to library" is _following = { this . inLibrary ( ) } / > : null }
2017-07-17 07:16:33 +12:00
{ this . props . slim _mode ? null : < ContextMenuTrigger className = "white" onTrigger = { e => this . handleContextMenu ( e ) } / > }
2017-02-27 07:31:58 +13:00
< / d i v >
2017-02-23 22:06:43 +13:00
{ this . renderSubViewMenu ( ) }
< / d i v >
2016-11-23 13:17:07 +13:00
< / d i v >
2017-06-18 05:47:36 +12:00
< div className = "content-wrapper" >
{ this . renderBody ( ) }
< / d i v >
2017-02-23 22:06:43 +13:00
< / d i v >
) ;
} else {
return (
< div className = "view artist-view" >
< SidebarToggleButton / >
< div className = "intro" >
< Parallax / >
< div className = "liner" >
2017-02-24 08:40:08 +13:00
< h1 >
< span className = "placeholder" > < / s p a n >
< / h 1 >
< div className = "actions" >
< button className = "placeholder" > & nbsp ; < / b u t t o n >
< button className = "placeholder" > & nbsp ; < / b u t t o n >
< / d i v >
2017-02-23 22:06:43 +13:00
{ this . renderSubViewMenu ( ) }
< / d i v >
< / d i v >
2017-06-18 05:47:36 +12:00
< div className = "content-wrapper" >
{ this . renderBody ( ) }
< / d i v >
2017-02-23 22:06:43 +13:00
< / d i v >
) ;
}
2016-11-01 16:41:04 +13:00
}
2016-10-17 10:39:11 +13:00
}
/ * *
* Export our component
*
* We also integrate our global store , using connect ( )
* * /
const mapStateToProps = ( state , ownProps ) => {
2016-11-09 21:13:40 +13:00
return {
2017-07-17 07:16:33 +12:00
slim _mode : state . ui . slim _mode ,
2017-05-22 04:19:44 +12:00
load _queue : state . ui . load _queue ,
2017-08-02 10:53:30 +12:00
artist : ( state . core . artists && typeof ( state . core . artists [ ownProps . params . uri ] ) !== 'undefined' ? state . core . artists [ ownProps . params . uri ] : false ) ,
artists : ( state . core . artists ? state . core . artists : [ ] ) ,
library _artists : ( state . core . library _artists ? state . core . library _artists : [ ] ) ,
albums : ( state . core . albums ? state . core . albums : [ ] ) ,
2016-11-18 10:02:05 +13:00
spotify _authorized : state . spotify . authorized ,
mopidy _connected : state . mopidy . connected
2016-11-09 21:13:40 +13:00
}
2016-10-17 10:39:11 +13:00
}
const mapDispatchToProps = ( dispatch ) => {
return {
2016-12-20 16:58:20 +13:00
uiActions : bindActionCreators ( uiActions , dispatch ) ,
2016-11-01 16:41:04 +13:00
mopidyActions : bindActionCreators ( mopidyActions , dispatch ) ,
2016-12-20 16:58:20 +13:00
pusherActions : bindActionCreators ( pusherActions , dispatch ) ,
2016-11-07 21:21:15 +13:00
lastfmActions : bindActionCreators ( lastfmActions , dispatch ) ,
2016-10-17 10:39:11 +13:00
spotifyActions : bindActionCreators ( spotifyActions , dispatch )
}
}
export default connect ( mapStateToProps , mapDispatchToProps ) ( Artist )