Localstorage woes again; multiple requests; creating common components

This commit is contained in:
James Barnsley
2016-10-18 21:57:29 +13:00
parent bd3ac79055
commit 51bf248ac9
14 changed files with 179 additions and 17 deletions

4
src/js/bootstrap.js vendored
View File

@ -21,6 +21,10 @@ var initialState = {
mopidy: {
host: window.location.hostname,
port: 6680
},
spotify: {
country: 'NZ',
locale: 'en_NZ'
}
};

28
src/js/components/AlbumGrid.js Executable file
View File

@ -0,0 +1,28 @@
import React, { PropTypes } from 'react'
import AlbumGridItem from './AlbumGridItem'
export default class AlbumGrid extends React.Component{
constructor(props) {
super(props);
}
render(){
if( this.props.items ){
return (
<ul className="grid album-grid">
{
this.props.items.items.map(
(album, index) => {
return <AlbumGridItem item={album} key={index} />
}
)
}
</ul>
);
}
return null;
}
}

View File

@ -0,0 +1,21 @@
import React, { PropTypes } from 'react'
import { Link } from 'react-router'
import Thumbnail from './Thumbnail'
export default class AlbumGridItem extends React.Component{
constructor(props) {
super(props);
}
render(){
var link = '/album/' + this.props.item.uri;
return (
<Link to={link} className="grid-item album-grid-item">
<Thumbnail size="medium" images={this.props.item.images} />
</Link>
);
}
}

26
src/js/components/Thumbnail.js Executable file
View File

@ -0,0 +1,26 @@
import React, { PropTypes } from 'react'
export default class Thumbnail extends React.Component{
constructor(props) {
super(props);
}
sizedImageURL(){
var images = this.props.images;
switch( this.props.size ){
case 'small':
break;
default:
return images[images.length-1].url
}
}
render(){
return (
<img src={ this.sizedImageURL() } />
);
}
}

View File

@ -14,12 +14,20 @@ const localstorageMiddleware = (function(){
case 'MOPIDY_SET_CONFIG':
var mopidy = {
host: action.host,
port: action.port
host: action.config.host,
port: action.config.port
};
localStorage.setItem('mopidy', JSON.stringify(mopidy));
break;
case 'SPOTIFY_SET_CONFIG':
var spotify = {
country: action.config.country,
locale: action.config.locale
};
localStorage.setItem('spotify', JSON.stringify(spotify));
break;
case 'SPOTIFY_COMPLETE_AUTHORIZATION':
var spotify = {
authorized: true,

View File

@ -3,6 +3,13 @@
* Actions and Action Creators
**/
export function setConfig( config ){
return {
type: 'MOPIDY_SET_CONFIG',
config: config
}
}
export function connect(){
return {
type: 'MOPIDY_CONNECT'
@ -15,14 +22,6 @@ export function disconnect(){
}
}
export function setConfig( host, port ){
return {
type: 'MOPIDY_SET_CONFIG',
host: host,
port: port
}
}
export function changeTrack( tlid ){
return {
type: 'MOPIDY_CHANGE_TRACK',

View File

@ -3,6 +3,13 @@
* Actions and Action Creators
**/
export function setConfig( config ){
return {
type: 'SPOTIFY_SET_CONFIG',
config: config
}
}
export function startAuthorization(){
return {
type: 'SPOTIFY_START_AUTHORIZATION'

View File

@ -33,8 +33,10 @@ const SpotifyMiddleware = (function(){
* The actual middleware inteceptor
**/
return store => next => action => {
switch(action.type) {
var state = store.getState();
switch(action.type){
case 'SPOTIFY_LOAD_ALBUM':
@ -57,21 +59,32 @@ const SpotifyMiddleware = (function(){
case 'SPOTIFY_LOAD_ARTIST':
store.dispatch({ type: 'SPOTIFY_ARTIST_LOADED', data: false })
store.dispatch({ type: 'SPOTIFY_ARTIST_ALBUMS_LOADED', data: false })
var id = action.uri.replace('spotify:artist:','');
sendRequest( false, 'artists/'+id )
.then( (response) => {
store.dispatch({ type: 'SPOTIFY_ARTIST_LOADED', data: response })
});
sendRequest( false, 'artists/'+id+'/albums' )
.then( (response) => {
store.dispatch({ type: 'SPOTIFY_ARTIST_ALBUMS_LOADED', data: response })
});
sendRequest( false, 'artists/'+id+'/top-tracks?country='+state.spotify.country )
.then( (response) => {
store.dispatch({ type: 'SPOTIFY_ARTIST_TRACKS_LOADED', data: response })
});
break;
case 'SPOTIFY_LOAD_LIBRARY_ARTISTS':
store.dispatch({ type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED', data: false })
var token = store.getState().spotify.access_token;
sendRequest( token, 'me/following?type=artist' )
sendRequest( state.spotify.access_token, 'me/following?type=artist' )
.then( (response) => {
store.dispatch({ type: 'SPOTIFY_LIBRARY_ARTISTS_LOADED', data: response })
});

View File

@ -35,6 +35,12 @@ export default function reducer(spotify = {}, action){
case 'SPOTIFY_ARTIST_LOADED':
return Object.assign({}, spotify, { artist: action.data });
case 'SPOTIFY_ARTIST_ALBUMS_LOADED':
return Object.assign({}, spotify, { artist_albums: action.data });
case 'SPOTIFY_ARTIST_TRACKS_LOADED':
return Object.assign({}, spotify, { artist_top_tracks: action.data });
case 'SPOTIFY_LIBRARY_ARTISTS_LOADED':
return Object.assign({}, spotify, { libraryArtists: action.data });

View File

@ -4,6 +4,8 @@ import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import TrackList from '../components/TrackList'
import AlbumGrid from '../components/AlbumGrid'
import * as spotifyActions from '../services/spotify/actions'
class Artist extends React.Component{
@ -30,6 +32,8 @@ class Artist extends React.Component{
<div>
<h3>{ this.props.spotify.artist.name }</h3>
<p>{ this.props.spotify.artist.followers.total.toLocaleString() } followers</p>
{ this.props.spotify.artist_top_tracks ? <TrackList tracks={ this.props.spotify.artist_top_tracks.tracks } /> : null }
{ this.props.spotify.artist_albums ? <AlbumGrid items={ this.props.spotify.artist_albums } /> : null }
</div>
);
}

View File

@ -17,7 +17,9 @@ class Settings extends React.Component{
this.state = {
mopidy_host: this.props.mopidy.host,
mopidy_port: this.props.mopidy.port
mopidy_port: this.props.mopidy.port,
spotify_country: this.props.spotify.country,
spotify_locale: this.props.spotify.locale
};
}
@ -26,17 +28,22 @@ class Settings extends React.Component{
window.location.reload(true);
}
setConfig(){
this.props.mopidyActions.setConfig( this.state.mopidy_host, this.state.mopidy_port );
setMopidyConfig(){
this.props.mopidyActions.setConfig({ host: this.state.mopidy_host, port: this.state.mopidy_port });
window.location.reload(true);
}
setSpotifyConfig(){
this.props.spotifyActions.setConfig({ country: this.state.spotify_country, locale: this.state.spotify_locale });
}
render(){
return (
<div>
<h3>Settings</h3>
<h4>Mopidy</h4>
<form onSubmit={() => this.setConfig()}>
<form onSubmit={() => this.setMopidyConfig()}>
<label>
<span className="label">Host</span>
<input onChange={ e => this.setState({ mopidy_host: e.target.value })} value={ this.state.mopidy_host } />
@ -47,8 +54,22 @@ class Settings extends React.Component{
</label>
<button type="submit">Apply</button>
</form>
<h4>Spotify</h4>
<form onSubmit={() => this.setSpotifyConfig()}>
<label>
<span className="label">Country</span>
<input onChange={ e => this.setState({ spotify_country: e.target.value })} value={ this.state.spotify_country } />
</label>
<label>
<span className="label">Locale</span>
<input onChange={ e => this.setState({ spotify_locale: e.target.value })} value={ this.state.spotify_locale } />
</label>
<button type="submit">Apply</button>
</form>
<SpotifyAuthenticationFrame />
<ConfirmationButton content="Reset all settings" confirmingContent="Are you sure?" onConfirm={() => this.resetAllSettings()} />
</div>
);

View File

@ -1,4 +1,8 @@
@import 'vendor/font-awesome/index';
@import 'global/reset';
@import 'global/forms';
@import 'components/track';

14
src/scss/global/_forms.scss Executable file
View File

@ -0,0 +1,14 @@
input {
padding: 5px 8px;
border: 1px solid #000000;
}
button,
input[type="button"],
input[type="submit"] {
padding: 5px 8px;
background: #000000;
color: #FFFFFF;
border: 0;
}

7
src/scss/global/_reset.scss Executable file
View File

@ -0,0 +1,7 @@
* {
border: 0;
margin: 0;
padding: 0;
outline: 0;
}