2016-10-17 10:39:11 +13:00
import React , { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
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 )
this . state = {
sub _view : 'overview'
}
2016-10-17 10:39:11 +13:00
}
componentDidMount ( ) {
2016-11-01 16:41:04 +13: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 )
}
}
}
2016-11-25 09:12:56 +13:00
componentWillUpdate ( nextProps , nextState ) {
2017-02-07 20:07:04 +13:00
if ( nextState . sub _view != this . state . sub _view && nextState . sub _view == 'about' ) {
2016-11-25 09:12:56 +13:00
if ( this . props . artist && ! this . props . artist . bio ) {
2017-01-15 21:06:24 +13:00
this . props . lastfmActions . getArtist ( this . props . params . uri , this . props . artist . name . replace ( '&' , 'and' ) )
2016-11-25 09:12:56 +13:00
}
}
}
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 {
this . props . spotifyActions . getArtist ( props . params . uri ) ;
}
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 {
this . props . mopidyActions . getArtist ( props . params . uri ) ;
}
}
2017-01-15 11:40:08 +13:00
break
2016-10-17 10:39:11 +13:00
}
2017-01-09 09:29:56 +13:00
// go back to overview
this . setState ( { sub _view : 'overview' } )
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" >
< span className = { 'option ' + ( this . state . sub _view == 'overview' ? 'active' : null ) } onClick = { ( ) => this . setState ( { sub _view : 'overview' } ) } >
Overview
< / s p a n >
2017-01-15 21:06:24 +13:00
{ this . props . artist . related _artists _uris ? < span className = { 'option ' + ( this . state . sub _view == 'related_artists' ? 'active' : null ) } onClick = { ( ) => this . setState ( { sub _view : 'related_artists' } ) } > Related artists < / s p a n > : n u l l }
2017-02-07 20:07:04 +13:00
< span className = { 'option ' + ( this . state . sub _view == 'about' ? 'active' : null ) } onClick = { ( ) => this . setState ( { sub _view : 'about' } ) } >
About
2016-11-23 13:17:07 +13:00
< / s p a n >
< / d i v >
)
}
2016-11-18 10:02:05 +13:00
2016-11-23 13:17:07 +13:00
renderBody ( ) {
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 ] )
}
}
}
2016-11-23 13:17:07 +13:00
if ( this . state . sub _view == 'related_artists' ) {
return (
2016-11-24 08:11:41 +13:00
< div className = "body related-artists" >
2016-11-23 13:17:07 +13:00
< h4 className = "left-padding" > Related artists < / h 4 >
< section className = "grid-wrapper no-top-padding" >
2017-01-14 10:03:45 +13:00
< ArtistGrid artists = { related _artists } / >
2016-11-23 13:17:07 +13:00
< / s e c t i o n >
2016-10-17 10:39:11 +13:00
< / d i v >
2016-11-23 13:17:07 +13:00
)
2017-02-07 20:07:04 +13:00
} else if ( this . state . sub _view == 'about' ) {
2016-11-23 21:42:56 +13:00
return (
2017-02-08 20:05:37 +13:00
< div className = "body about" >
2017-02-08 19:31:36 +13:00
< div className = "col w40 tiles" >
2017-03-22 18:41:31 +13:00
{ this . props . artist . images _additional ? < div className = "tile thumbnail-wrapper" > < Thumbnail size = "large" canZoom images = { this . props . artist . images _additional } / > < / d i v > : n u l l }
2017-02-08 20:05:37 +13:00
{ this . props . artist . followers ? < div className = "tile" > < span className = "text" > < 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 = "text" > < 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 = "text" > < FontAwesome name = "headphones" / > { this . props . artist . listeners . toLocaleString ( ) } listeners < / s p a n > < / d i v > : n u l l }
2017-02-08 19:31:36 +13:00
< / d i v >
< div className = "col w60 biography" >
2017-02-08 21:13:20 +13:00
< h4 > Biography < / h 4 >
< section >
{ this . props . artist . bio ? < div className = "biography-text" > < p > { this . props . artist . bio . content } < /p><br / >
2017-02-08 19:31:36 +13:00
< 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 >
2016-11-23 21:42:56 +13:00
< / d i v >
)
2016-11-23 13:17:07 +13:00
}
2016-11-01 16:41:04 +13:00
2016-11-23 13:17:07 +13:00
return (
2016-11-24 08:11:41 +13:00
< div className = "body overview" >
2017-01-16 08:11:32 +13:00
< div className = { related _artists . length > 0 ? "col w70" : "col w100" } >
2016-11-01 16:41:04 +13:00
< h4 className = "left-padding" > Top tracks < / h 4 >
2017-02-10 22:22:33 +13:00
< div className = "list-wrapper" >
2017-03-13 13:17:11 +13:00
{ this . props . artist . tracks ? < TrackList className = "artist-track-list" uri = { this . props . params . uri } tracks = { this . props . artist . tracks } / > : null }
2017-02-10 22:22:33 +13:00
< / d i v >
2016-11-01 16:41:04 +13:00
< / d i v >
< div className = "col w5" > < / d i v >
2017-03-13 21:19:09 +13: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)} / > < / d i v > < / d i v > : n u l l }
2016-11-01 16:41:04 +13:00
< div className = "cf" > < / d i v >
< h4 className = "left-padding" > Albums < / h 4 >
2016-11-07 21:21:15 +13:00
< section className = "grid-wrapper no-top-padding" >
2017-01-14 10:03:45 +13:00
< AlbumGrid albums = { albums } / >
2017-01-27 08:15:59 +13:00
< LazyLoadListener enabled = { this . props . artist . albums _more } loadMore = { ( ) => this . loadMore ( ) } / >
2016-11-07 21:21:15 +13:00
< / s e c t i o n >
2016-11-01 16:41:04 +13:00
< / d i v >
2016-11-23 13:17:07 +13:00
)
}
render ( ) {
var scheme = helpers . uriSource ( this . props . params . uri ) ;
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-02-23 22:06:43 +13:00
< SidebarToggleButton / >
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-02-23 22:06:43 +13:00
< Parallax image = { image } / >
2016-11-23 13:17:07 +13:00
2017-02-23 22:06:43 +13:00
< div className = "liner" >
2017-03-22 15:32:55 +13:00
< Thumbnail image = { image } canZoom circle / >
2017-02-23 22:06:43 +13:00
< h1 > { this . props . artist ? this . props . artist . name : null } < / h 1 >
2017-02-27 07:31:58 +13:00
< div className = "actions" >
{ can _play _radio ? < button className = "primary" onClick = { e => this . props . pusherActions . startRadio ( [ this . props . artist . uri ] ) } > Start radio < / b u t t o n > : n u l l }
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-02-28 16:13:27 +13:00
< 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-02-23 22:06:43 +13:00
{ this . props . artist ? this . renderBody ( ) : null }
2016-11-23 13:17:07 +13:00
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" >
< Thumbnail circle / >
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 >
< / 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-01-14 22:32:39 +13:00
artist : ( state . ui . artists && typeof ( state . ui . artists [ ownProps . params . uri ] ) !== 'undefined' ? state . ui . artists [ ownProps . params . uri ] : false ) ,
2017-03-24 16:06:49 +13:00
artists : ( state . ui . artists ? state . ui . artists : [ ] ) ,
library _artists : ( state . ui . library _artists ? state . ui . library _artists : [ ] ) ,
albums : ( state . ui . albums ? state . ui . 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 )