Persistent storage; Authorization via spotify
This commit is contained in:
@ -1,12 +0,0 @@
|
||||
|
||||
/**
|
||||
* Actions and Action Creators
|
||||
**/
|
||||
|
||||
export const LOAD_ALBUMS = 'LOAD_ALBUMS'
|
||||
|
||||
export function loadAlbums(){
|
||||
return {
|
||||
type: LOAD_ALBUMS
|
||||
}
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
|
||||
import albumActions from './albumActions'
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
|
||||
/**
|
||||
* Actions and Action Creators
|
||||
**/
|
||||
|
||||
export const AUTHORIZE_SPOTIFY = 'AUTHORIZE_SPOTIFY'
|
||||
export const AUTHORIZE_SPOTIFY_SUCCESS = 'AUTHORIZE_SPOTIFY_SUCCESS'
|
||||
export const MOPIDY_ONLINE = 'MOPIDY_ONLINE'
|
||||
|
||||
export function authorizeSpotify( authorize = true ){
|
||||
return {
|
||||
type: AUTHORIZE_SPOTIFY,
|
||||
authorize: authorize
|
||||
}
|
||||
}
|
||||
|
||||
export function authorizeSpotifySuccess( authorization ){
|
||||
return {
|
||||
type: AUTHORIZE_SPOTIFY_SUCCESS,
|
||||
authorization: authorization
|
||||
}
|
||||
}
|
||||
|
||||
export function mopidyOnline( online ){
|
||||
return {
|
||||
type: MOPIDY_ONLINE,
|
||||
online: online
|
||||
}
|
||||
}
|
||||
11
src/js/bootstrap.js
vendored
11
src/js/bootstrap.js
vendored
@ -9,16 +9,23 @@ import spotify from './services/spotify/reducer'
|
||||
import thunk from 'redux-thunk'
|
||||
import mopidyMiddleware from './services/mopidy/middleware'
|
||||
import spotifyMiddleware from './services/spotify/middleware'
|
||||
import localstorageMiddleware from './services/localstorageMiddleware'
|
||||
|
||||
let reducers = combineReducers({
|
||||
mopidy,
|
||||
spotify
|
||||
});
|
||||
|
||||
// load our state from localStorage
|
||||
var initialState = {};
|
||||
if( localStorage.getItem('state') ){
|
||||
initialState = JSON.parse( localStorage.getItem('state') );
|
||||
}
|
||||
|
||||
let store = createStore(
|
||||
reducers,
|
||||
{},
|
||||
applyMiddleware( thunk, mopidyMiddleware, spotifyMiddleware )
|
||||
initialState,
|
||||
applyMiddleware( thunk, localstorageMiddleware, mopidyMiddleware, spotifyMiddleware )
|
||||
);
|
||||
|
||||
export default store;
|
||||
|
||||
56
src/js/components/Artist.js
Executable file
56
src/js/components/Artist.js
Executable file
@ -0,0 +1,56 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
|
||||
import TrackList from './TrackList'
|
||||
import * as spotifyActions from '../services/spotify/actions'
|
||||
|
||||
class Artist extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
// on render
|
||||
componentDidMount(){
|
||||
this.props.spotifyActions.loadArtist( this.props.params.uri );
|
||||
}
|
||||
|
||||
// when props changed
|
||||
componentWillReceiveProps( nextProps ){
|
||||
if( nextProps.params.uri != this.props.params.uri ){
|
||||
this.props.spotifyActions.loadArtist( nextProps.params.uri );
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
if( this.props.spotify.artist ){
|
||||
return (
|
||||
<div>
|
||||
<h3>{ this.props.spotify.artist.name }</h3>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export our component
|
||||
*
|
||||
* We also integrate our global store, using connect()
|
||||
**/
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return state;
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Artist)
|
||||
39
src/js/components/ConfirmationButton.js
Executable file
39
src/js/components/ConfirmationButton.js
Executable file
@ -0,0 +1,39 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import FontAwesome from 'react-fontawesome'
|
||||
|
||||
export default class ConfirmationButton extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
confirming: false
|
||||
}
|
||||
}
|
||||
|
||||
handleClick(e){
|
||||
if( this.state.confirming ){
|
||||
this.setState({ confirming: false });
|
||||
this.props.onConfirm();
|
||||
}else{
|
||||
this.setState({ confirming: true });
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
var className = 'button';
|
||||
var content = this.props.content;
|
||||
|
||||
if( this.state.confirming ){
|
||||
className += ' confirming';
|
||||
content = this.props.confirmingContent;
|
||||
}
|
||||
|
||||
return (
|
||||
<span className={className} onClick={ (e) => this.handleClick(e) }>
|
||||
{ content }
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { createStore, bindActionCreators } from 'redux'
|
||||
import FontAwesome from 'react-fontawesome'
|
||||
|
||||
import * as actions from '../services/spotify/actions'
|
||||
|
||||
@ -11,9 +12,40 @@ class SpotifyAuthenticationFrame extends React.Component{
|
||||
super(props);
|
||||
}
|
||||
|
||||
handleClick(e){
|
||||
console.log('handling click')
|
||||
this.props.actions.authorize();
|
||||
componentDidMount(){
|
||||
|
||||
let self = this;
|
||||
|
||||
// listen for incoming messages from the authorization iframe
|
||||
// this is triggered when authentication is granted from the popup
|
||||
window.addEventListener('message', function(event){
|
||||
|
||||
// only allow incoming data from our authorized authenticator proxy
|
||||
if( !/^https?:\/\/jamesbarnsley\.co\.nz/.test(event.origin) ) return false;
|
||||
|
||||
var data = JSON.parse(event.data);
|
||||
self.props.actions.completeAuthorization( data );
|
||||
|
||||
}, false);
|
||||
}
|
||||
|
||||
renderAuthorizeButton(){
|
||||
if( this.props.spotify.authorizing ){
|
||||
return (
|
||||
<span>
|
||||
<FontAwesome name="circle-o-notch" spin />
|
||||
<span>Authorizing...</span>
|
||||
</span>
|
||||
);
|
||||
}else if( this.props.spotify.authorization ){
|
||||
return (
|
||||
<button onClick={() => this.props.actions.removeAuthorization()}>Log out</button>
|
||||
);
|
||||
}else{
|
||||
return (
|
||||
<button onClick={() => this.props.actions.startAuthorization()}>Log in</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
@ -23,7 +55,7 @@ class SpotifyAuthenticationFrame extends React.Component{
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<button onClick={(e) => this.handleClick(e)}>Authorize</button>
|
||||
{ this.renderAuthorizeButton() }
|
||||
<iframe src={src}></iframe>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -9,17 +9,24 @@ import { createStore } from 'redux'
|
||||
import { Router, Route, Link, hashHistory } from 'react-router'
|
||||
|
||||
import store from './bootstrap.js'
|
||||
import App from './components/App'
|
||||
import Album from './components/Album'
|
||||
import Queue from './components/Queue'
|
||||
|
||||
import App from './views/App'
|
||||
import Album from './views/Album'
|
||||
import Artist from './views/Artist'
|
||||
import Queue from './views/Queue'
|
||||
import Settings from './views/Settings'
|
||||
import LibraryArtists from './views/LibraryArtists'
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<Router history={hashHistory}>
|
||||
<Route path="/" component={App}>
|
||||
|
||||
<Route path="library/artists" component={LibraryArtists} />
|
||||
<Route path="album/:uri" component={Album} />
|
||||
<Route path="artist/:uri" component={Artist} />
|
||||
<Route path="queue" component={Queue} />
|
||||
<Route path="settings" component={Settings} />
|
||||
|
||||
</Route>
|
||||
</Router>
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
|
||||
import * as actions from '../actions/albumActions'
|
||||
|
||||
export default function album(album = {}, action) {
|
||||
switch (action.type) {
|
||||
|
||||
case actions.LOAD_ALBUM:
|
||||
return album//Object.assign({}, album, action.album);
|
||||
|
||||
default:
|
||||
return album
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Root reducer
|
||||
*
|
||||
* This combines all our application reducers into a single, top-level reducer.
|
||||
* We need to combine reducers to create the unified application-level store.
|
||||
**/
|
||||
|
||||
// import all of our application reducers
|
||||
import album from './album'
|
||||
import mopidy from '../services/mopidy/reducer'
|
||||
|
||||
import { combineReducers } from 'redux'
|
||||
|
||||
// combine them into one root reducer
|
||||
export default combineReducers({
|
||||
album,
|
||||
mopidy
|
||||
})
|
||||
|
||||
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
|
||||
import * as actions from './actions'
|
||||
|
||||
export default function reducer(state = {}, action){
|
||||
switch (action.type) {
|
||||
|
||||
case actions.AUTHORIZE_SPOTIFY:
|
||||
return Object.assign({}, state.spotify, {
|
||||
authorizing: action.authorize
|
||||
});
|
||||
|
||||
case actions.AUTHORIZE_SPOTIFY_SUCCESS:
|
||||
console.info('Spotify authorization successful');
|
||||
var state = Object.assign({}, state.spotify, action.authorization)
|
||||
state = Object.assign({}, state.spotify, { online: true, authorizingSpotify: false })
|
||||
return state
|
||||
|
||||
case actions.MOPIDY_ONLINE:
|
||||
return Object.assign({}, state.mopidy, {
|
||||
online: action.online
|
||||
});
|
||||
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
20
src/js/services/localstorageMiddleware.js
Executable file
20
src/js/services/localstorageMiddleware.js
Executable file
@ -0,0 +1,20 @@
|
||||
|
||||
const localstorageMiddleware = (function(){
|
||||
|
||||
/**
|
||||
* The actual middleware inteceptor
|
||||
**/
|
||||
return store => next => action => {
|
||||
|
||||
// proceed as normal first
|
||||
// this way, any reducers and middleware do their thing BEFORE we store our new state
|
||||
next(action);
|
||||
|
||||
// get the state, and plug it in to our localStorage
|
||||
var state = store.getState();
|
||||
localStorage.setItem('state', JSON.stringify(state));
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
export default localstorageMiddleware
|
||||
@ -104,8 +104,11 @@ const MopidyMiddleware = (function(){
|
||||
if(socket != null) socket.close();
|
||||
store.dispatch({ type: 'MOPIDY_CONNECTING' });
|
||||
|
||||
var domain = "tv.barnsley.nz";
|
||||
if( window.location.hostname == 'iris.james' ) domain = 'music.james';
|
||||
|
||||
socket = new Mopidy({
|
||||
webSocketUrl: "ws://tv.barnsley.nz:6680/mopidy/ws",
|
||||
webSocketUrl: 'ws://'+domain+':6680/mopidy/ws',
|
||||
callingConvention: 'by-position-or-by-name'
|
||||
});
|
||||
|
||||
|
||||
@ -3,9 +3,22 @@
|
||||
* Actions and Action Creators
|
||||
**/
|
||||
|
||||
export function authorize(){
|
||||
export function startAuthorization(){
|
||||
return {
|
||||
type: 'SPOTIFY_AUTHORIZING'
|
||||
type: 'SPOTIFY_START_AUTHORIZATION'
|
||||
}
|
||||
}
|
||||
|
||||
export function removeAuthorization(){
|
||||
return {
|
||||
type: 'SPOTIFY_REMOVE_AUTHORIZATION'
|
||||
}
|
||||
}
|
||||
|
||||
export function completeAuthorization( data ){
|
||||
return {
|
||||
type: 'SPOTIFY_COMPLETE_AUTHORIZATION',
|
||||
data: data
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,3 +41,10 @@ export function loadAlbum( uri ){
|
||||
}
|
||||
}
|
||||
|
||||
export function loadArtist( uri ){
|
||||
return {
|
||||
type: 'SPOTIFY_LOAD_ARTIST',
|
||||
uri: uri
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,30 +3,56 @@ import actions from './actions'
|
||||
|
||||
const SpotifyMiddleware = (function(){
|
||||
|
||||
return store => next => action => {
|
||||
/**
|
||||
* Send an ajax request to the Spotify API
|
||||
*
|
||||
* @param endpoint string = the url to query (ie /albums/:uri)
|
||||
* @param method string
|
||||
* @param data mixed = request payload
|
||||
* @return ajax promise
|
||||
**/
|
||||
const sendRequest = (endpoint, method = 'GET', data = false) => {
|
||||
return $.ajax({
|
||||
method: method,
|
||||
cache: true,
|
||||
url: 'https://api.spotify.com/v1/'+endpoint,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual middleware inteceptor
|
||||
**/
|
||||
return store => next => action => {
|
||||
switch(action.type) {
|
||||
|
||||
|
||||
case 'SPOTIFY_LOAD_ALBUM':
|
||||
|
||||
// clear the current album
|
||||
store.dispatch({ type: 'SPOTIFY_ALBUM_LOADED', data: false })
|
||||
|
||||
var id = action.uri.replace('spotify:album:','');
|
||||
$.ajax({
|
||||
method: 'GET',
|
||||
cache: true,
|
||||
url: 'https://api.spotify.com/v1/albums/'+id,
|
||||
success: function(album){
|
||||
store.dispatch({ type: 'SPOTIFY_ALBUM_LOADED', data: album })
|
||||
}
|
||||
});
|
||||
|
||||
sendRequest('albums/'+id)
|
||||
.then( (response) => {
|
||||
store.dispatch({ type: 'SPOTIFY_ALBUM_LOADED', data: response })
|
||||
});
|
||||
break;
|
||||
|
||||
|
||||
case 'SPOTIFY_LOAD_ARTIST':
|
||||
|
||||
store.dispatch({ type: 'SPOTIFY_ARTIST_LOADED', data: false })
|
||||
var id = action.uri.replace('spotify:artist:','');
|
||||
|
||||
sendRequest('artists/'+id)
|
||||
.then( (response) => {
|
||||
store.dispatch({ type: 'SPOTIFY_ARTIST_LOADED', data: response })
|
||||
});
|
||||
break;
|
||||
|
||||
|
||||
case 'SPOTIFY_CONNECT':
|
||||
|
||||
console.log('Spotify wants to connect')
|
||||
|
||||
break;
|
||||
|
||||
case 'SPOTIFY_DISCONNECT':
|
||||
|
||||
@ -5,9 +5,15 @@ export default function reducer(spotify = {}, action){
|
||||
case 'SPOTIFY_CONNECTING':
|
||||
return Object.assign({}, spotify, { connected: false, connecting: true });
|
||||
|
||||
case 'SPOTIFY_AUTHORIZING':
|
||||
case 'SPOTIFY_START_AUTHORIZATION':
|
||||
return Object.assign({}, spotify, { authorizing: true });
|
||||
|
||||
case 'SPOTIFY_COMPLETE_AUTHORIZATION':
|
||||
return Object.assign({}, spotify, { authorizing: false, authorization: action.data });
|
||||
|
||||
case 'SPOTIFY_REMOVE_AUTHORIZATION':
|
||||
return Object.assign({}, spotify, { authorizing: false, authorization: false });
|
||||
|
||||
case 'SPOTIFY_CONNECTED':
|
||||
return Object.assign({}, spotify, { connected: true, connecting: false });
|
||||
|
||||
@ -17,6 +23,12 @@ export default function reducer(spotify = {}, action){
|
||||
case 'SPOTIFY_ALBUM_LOADED':
|
||||
return Object.assign({}, spotify, { album: action.data });
|
||||
|
||||
case 'SPOTIFY_ARTIST_LOADED':
|
||||
return Object.assign({}, spotify, { artist: action.data });
|
||||
|
||||
case 'SPOTIFY_LIBRARY_ARTISTS_LOADED':
|
||||
return Object.assign({}, spotify, { library_artists: action.data });
|
||||
|
||||
default:
|
||||
return spotify
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
|
||||
import TrackList from './TrackList'
|
||||
import TrackList from '../components/TrackList'
|
||||
import * as spotifyActions from '../services/spotify/actions'
|
||||
|
||||
class Album extends React.Component{
|
||||
@ -5,10 +5,10 @@ import { createStore, bindActionCreators } from 'redux'
|
||||
import { Link } from 'react-router'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import * as actions from '../actions/index'
|
||||
import Player from '../components/Player'
|
||||
|
||||
import * as mopidyActions from '../services/mopidy/actions'
|
||||
import * as spotifyActions from '../services/spotify/actions'
|
||||
import SpotifyAuthenticationFrame from './SpotifyAuthenticationFrame'
|
||||
|
||||
|
||||
/**
|
||||
@ -30,10 +30,11 @@ class App extends React.Component{
|
||||
<div>
|
||||
<ul role="nav">
|
||||
<li><Link to="/queue">Now playing</Link></li>
|
||||
<li><Link to="/library/albums">Library: Albums</Link></li>
|
||||
<li><Link to="/library/artists">Library: My artists</Link></li>
|
||||
<li><Link to="/settings">Settings</Link></li>
|
||||
</ul>
|
||||
<SpotifyAuthenticationFrame />
|
||||
{this.props.children}
|
||||
<Player />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -51,7 +52,6 @@ const mapStateToProps = (state, ownProps) => {
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
actions: bindActionCreators(actions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
56
src/js/views/Artist.js
Executable file
56
src/js/views/Artist.js
Executable file
@ -0,0 +1,56 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
|
||||
import TrackList from '../components/TrackList'
|
||||
import * as spotifyActions from '../services/spotify/actions'
|
||||
|
||||
class Artist extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
// on render
|
||||
componentDidMount(){
|
||||
this.props.spotifyActions.loadArtist( this.props.params.uri );
|
||||
}
|
||||
|
||||
// when props changed
|
||||
componentWillReceiveProps( nextProps ){
|
||||
if( nextProps.params.uri != this.props.params.uri ){
|
||||
this.props.spotifyActions.loadArtist( nextProps.params.uri );
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
if( this.props.spotify.artist ){
|
||||
return (
|
||||
<div>
|
||||
<h3>{ this.props.spotify.artist.name }</h3>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export our component
|
||||
*
|
||||
* We also integrate our global store, using connect()
|
||||
**/
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return state;
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Artist)
|
||||
45
src/js/views/LibraryArtists.js
Executable file
45
src/js/views/LibraryArtists.js
Executable file
@ -0,0 +1,45 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
|
||||
import * as mopidyActions from '../services/mopidy/actions'
|
||||
import * as spotifyActions from '../services/spotify/actions'
|
||||
|
||||
import TrackList from '../components/TrackList'
|
||||
|
||||
class LibraryArtists extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
// on render
|
||||
componentDidMount(){
|
||||
this.props.spotifyActions.loadLibraryArtists();
|
||||
}
|
||||
|
||||
render(){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export our component
|
||||
*
|
||||
* We also integrate our global store, using connect()
|
||||
**/
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return state;
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(LibraryArtists)
|
||||
@ -44,9 +44,9 @@ class Queue extends React.Component{
|
||||
<div>
|
||||
<h3>Now playing</h3>
|
||||
{ this.renderTrackInFocus() }
|
||||
<Player />
|
||||
<h4>Other tracks</h4>
|
||||
{ this.renderTrackList() }
|
||||
<Player />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
53
src/js/views/Settings.js
Executable file
53
src/js/views/Settings.js
Executable file
@ -0,0 +1,53 @@
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
|
||||
import FontAwesome from 'react-fontawesome'
|
||||
import SpotifyAuthenticationFrame from '../components/SpotifyAuthenticationFrame'
|
||||
import ConfirmationButton from '../components/ConfirmationButton'
|
||||
|
||||
import * as mopidyActions from '../services/mopidy/actions'
|
||||
import * as spotifyActions from '../services/spotify/actions'
|
||||
|
||||
class Settings extends React.Component{
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
resetAllSettings(){
|
||||
localStorage.removeItem('state');
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div>
|
||||
<h3>Settings</h3>
|
||||
<SpotifyAuthenticationFrame />
|
||||
<ConfirmationButton content="Reset all settings" confirmingContent="Are you sure?" onConfirm={() => this.resetAllSettings()} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export our component
|
||||
*
|
||||
* We also integrate our global store, using connect()
|
||||
**/
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return state;
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Settings)
|
||||
Reference in New Issue
Block a user