transcend-spotify-react
Version:
A react component to explore Spotify data using Transcend
273 lines (226 loc) • 8.3 kB
JavaScript
import React from 'react'
import { dateFormatter } from 'transcend-formats';
import { guid } from 'transcend-helpers';
import {SpotifySavedTracksComponent, SpotifyFollowedArtistsComponent, SpotifySavedPlaylistsComponent,
SpotifyTopTracksComponent, SpotifyTopArtistsComponent, SpotifyPlayHistoryComponent, SpotifyAllTracksComponent,
SpotifyAllArtistsComponent, SpotifyAllFriendsComponent} from 'transcend-spotify-components-react'
class User {
constructor(userObj, parent){
this.alwaysThisUser = ["allTracks", "allArtists", "allFriends"];
this.data = userObj.data;
this.friends = userObj.friends;
this.parent = parent;
}
getFriendData(ind){
return this.friends[ind];
}
getDisplayUser(){
if(this.parent.state.displayUser === -1 || this.alwaysThisUser.indexOf(this.parent.state.displayType) > -1) return this.data;
else return this.getFriendData(this.parent.state.displayUser);
}
renderProfile(){
let user = this.getDisplayUser();
return (<div>
<div>
{user.details.images.length > 0 &&
<img src={user.details.images[0].url} />
}
</div>
<div>
{user.details.display_name}
</div>
<div>
Num Followers: {user.details.followers.total}
</div>
</div>);
}
}
/**
* Display Spotify Table
**/
class SpotifyTable extends React.Component {
// Sub components
state = {
components: [SpotifySavedTracksComponent, SpotifyFollowedArtistsComponent, SpotifySavedPlaylistsComponent,
SpotifyTopTracksComponent, SpotifyTopArtistsComponent, SpotifyPlayHistoryComponent,
SpotifyAllTracksComponent, SpotifyAllArtistsComponent, SpotifyAllFriendsComponent],
instantiatedComponents: {},
display : [],
displayParent: [],
displayUser : -1,
displayType: "allTracks",
displayPull: 0,
displayState: {},
displayStates : {},
plotOptions: {
key : "popularity",
plotLocation: "profile",
type : "pdf",
numBins : 20,
standardize : false,
allowedTypes : []
}
};
constructor(props) {
super(props);
this.user = new User(this.props.userData, this);
// Instantiate components
this.state.components.map((Component) => {
let instantiatedComponent = new Component({user : this.user, parent : this});
this.state.displayState[instantiatedComponent.state.key] = instantiatedComponent.state.displayState;
this.state.displayStates[instantiatedComponent.state.key] = instantiatedComponent.state.displayStates;
this.state.instantiatedComponents[instantiatedComponent.state.key] = instantiatedComponent;
})
}
componentDidMount() {
let hash = location.hash.substring(1);
if(hash.length > 0) this.setState({ displayType : hash});
else location.hash = "#" + this.state.displayType;
}
/**
* Build the User Profile
**/
getCurrentComponent(){
return this.state.instantiatedComponents[this.state.displayType];
}
updateAllowedTypes(){
let component = this.getCurrentComponent();
if(component.state.displayStates && component.state.displayStates[this.state.displayType]){
this.state.plotOptions.allowedTypes = component.state.displayStates[this.state.displayType].plot;
}
}
buildProfile(){
this.updateAllowedTypes();
return (<div>
{ this.user.renderProfile() }
{ this.state.plotOptions.plotLocation === "profile" &&
<div className="plotSpace"> {this.getCurrentComponent().plot(this.state.plotOptions) } </div>
}
</div>);
}
/**
* Build Menus
**/
buildHeader(){
let main = <ul key={guid()} className="nav">
{ Object.keys(this.state.instantiatedComponents).map((key, ind) => {
return <li key={guid()}>
<a href={"#" + key} onClick={this.switchDisplayType.bind(this, key)}
className={(this.state.displayType === key ? "nav-selected " : "") + "nav-item"}>
- {this.state.instantiatedComponents[key].state.displayName } -
</a>
</li>;
})}
</ul>;
let headers = this.state.instantiatedComponents[this.state.displayType].state.headers;
let others = <span key={guid()} >
{ headers.map((header, ind) => {
return this.buildMenu(header);
})}
</span>;
return <div>
{main}
{others}
</div>
}
buildMenu(menuName){
let user = this.user.getDisplayUser();
switch(menuName){
case "friends":
return <ul key={guid()} className="nav">
<li key={guid()} onClick={this.switchToSelf.bind(this)}><a className={(user.userId === this.user.data.userId ? "nav-selected " : "") + "nav-item"}>- Me -</a></li>
{ this.user.friends.map((friend, ind) => {
return <li key={guid()} onClick={this.switchUser.bind(this, ind)}><a className={(user.userId === friend.userId ? "nav-selected " : "") + "nav-item"}>- {friend.details.display_name} -</a></li>
})}
</ul>;
case "pullHistory":
let pullLists = user[this.state.displayType];
return <div/>;
<ul key={guid()} className="nav">
{ user[this.state.displayType].map((pulledList, ind) => {
return <div>
<li key={guid()} onClick={this.switchPull.bind(this, ind)}><a className="nav-item">- {dateFormatter(new Date(pulledList.timePulled))} -</a></li>
</div>;
})}
</ul>
case "collapser":
let displayState = this.state.displayState[this.state.displayType];
let displayStates = this.state.displayStates[this.state.displayType];
return <div key={guid()}>
{ Object.keys(displayState).map((key) => {
return <ul key={guid()} className="nav">
<label>{ displayStates[key]['displayName'] }: -</label>
{displayStates[key]["plot"].length > 0 &&
<li key={guid()} onClick={this.switchPlotOption.bind(this, "key", key)}><a className={(this.state.plotOptions.key === key ? "nav-selected " : "") + "nav-item"}>- Plot -</a></li>
}
<li key={guid()} onClick={this.switchDisplay.bind(this, key, "none")}><a className={(displayState[key].length === 0 ? "nav-selected " : "") + "nav-item"}>- Hide -</a></li>
{ displayStates[key]['states'].map((state, ind) => {
return <li key={guid()} onClick={this.switchDisplay.bind(this, key, state)}><a className={(displayState[key].indexOf(state) > -1 ? "nav-selected " : "") + "nav-item"}>- { state } -</a></li>;
})}
</ul>;
})}
</div>;
}
}
/**
* Changing State
**/
switchPlotOption(key, value){
let plotOptions = this.state.plotOptions;
plotOptions[key] = value;
this.setState({plotOptions : plotOptions});
}
switchUser(id){
this.setState({displayUser :id});
}
switchToSelf(){
this.setState({displayUser :-1});
}
switchDisplayType(newType){
this.setState({displayType :newType});
}
switchPull(id){
this.setState({displayPull :id});
}
switchDisplay(stateName, stateValue){
let newState = this.state.displayState;
let changeState = newState[this.state.displayType][stateName];
if(stateValue === "none"){
changeState = []
}
else{
let index = changeState.indexOf(stateValue);
if(index === -1){
changeState.push(stateValue);
}
else{
changeState.splice(index, 1);
}
}
newState[this.state.displayType][stateName] = changeState;
this.setState({displayState : newState});
}
/**
* Render
**/
render() {
let header = this.buildHeader();
let profile = this.buildProfile();
return <div className={"row"}>
<div className={"col-lg-6"}>
{header}
</div>
<div className={"col-lg-6"}>
{profile}
</div>
{ this.state.plotOptions.plotLocation === "fullWidth" &&
<div className="plotSpace col-lg-12"> {this.getCurrentComponent().plot(this.state.plotOptions) } </div>
}
{ this.state.instantiatedComponents[this.state.displayType].render() }
</div>;
}
}
module.exports = {
User : User,
SpotifyTable : SpotifyTable
}