Jamming Project: Playlist not saving

Hey everyone -
I am having an issue saving playlists - nothing happens, at all, when I click ‘save playlist’. I don’t even get any errors in the console.
That being said, I do have a general error in the console when I load the page. It says “Error while trying to use the 3000/#access_token= …”
Any thoughts would be appreciated.

App.js:

import React from 'react';
import './App.css';

import SearchBar from '../SearchBar/SearchBar';
import SearchResults from '../SearchResults/SearchResults';
import Playlist from '../Playlist/Playlist';
import Spotify from '../../util/Spotify';

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      searchResults: [],
      playlistName: 'my playlist',
      playlistTracks: []
    };

    this.addTrack = this.addTrack.bind(this);
    this.removeTrack = this.removeTrack.bind(this);
    this.updatePlaylistName = this.updatePlaylistName.bind(this);
    this.savePlayList = this.savePlayList.bind(this);
    this.search = this.search.bind(this);
  }

  addTrack(track) {
    let tracks = this.state.playlistTracks;
    if (tracks.find(savedTrack => savedTrack.id === track.id)) {
      return;
    } else {
      tracks.push(track)
      this.setState({ playlistTracks: tracks })
    }
  }

  removeTrack(track) {
    let tracks = this.state.playlistTracks;
    tracks = tracks.filter(currentTrack => currentTrack.id !== track.id);

    this.setState({ playlistTracks: tracks });
  }


  updatePlaylistName(name) {
    this.setState({ playlistName: name })
  }

  savePlayList() {
    const trackURIs = this.state.playlistTracks.map(track => track.uri);
    Spotify.savePlaylist(this.state.playlistName, trackURIs).then(() => {
      this.setState({
        playlistName: 'New Playlist',
        playlistTracks: []
      })
    })
  }

  search(term) {
    Spotify.search(term).then(searchResults => {
      this.setState({ searchResults: searchResults })
    })
  }

  render() {
    return (
      <div>
        <h1>Ja<span className="highlight">mmm</span>ing</h1>
        <div className="App">
          <SearchBar onSearch={this.search} />
          <div className="App-playlist">
            <SearchResults searchResults={this.state.searchResults}
              onAdd={this.addTrack} />
            <Playlist playlistName={this.state.playlistName}
              playlistTracks={this.state.playlistTracks}
              onRemove={this.removeTrack}
              onNameChange={this.updatePlaylistName}
              onSave={this.savePlaylist}
            />
          </div>
        </div>
      </div>
    );
  }
}


export default App;

Spotify.js:

const clientID = '***';
const redirectUri = 'http://localhost:3000/';

let accessToken;

const Spotify = {

    getaccessToken() {

        if (this.accessToken) {
            return accessToken;
        }

        // check for  token match

        const accessTokenMatch = window.location.href.match(/access_token=([^&]*)/);
        const expiresInMatch = window.location.href.match(/expires_in=([^&]*)/);
        if (accessTokenMatch && expiresInMatch) {
            accessToken = accessTokenMatch[1];
            const expiresIn = Number(expiresInMatch[0])

            window.setTimeout(() => accessToken = '', expiresIn * 6000);


            return accessToken;

        } else {

            const accessUrl = `https://accounts.spotify.com/authorize?client_id=${clientID}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirectUri}`;
            window.location = accessUrl;
        }
    },

    search(term) {

        const accessToken = Spotify.getaccessToken();
        const headers = {
            Authorization: `Bearer ${accessToken}`
        }

        return fetch(`https://api.spotify.com/v1/search?type=track&q=${term}`, { headers: headers }
        ).then(response => {
            return response.json();
        }).then(jsonResponse => {
            if (!jsonResponse.tracks) {
                return [];
            }
            return jsonResponse.tracks.items.map(track => ({
                id: track.id,
                name: track.name,
                artist: track.artists[0].name,
                album: track.album.name,
                uri: track.uri

            }))

        });
    },

    savePlayList(name, trackURIs) {
        if (!name || !trackURIs.length) {
            return;
        }

        const accessToken = Spotify.getaccessToken();
        console.log(`savePlaylist() accessToken - ${accessToken}`);
        const headers = {
            Authorization: `Bearer ${accessToken}`
        }

        let userId;
        return fetch(`https://api.spotify.com/v1/me`, { headers: headers }
        ).then(response => response.json()
        ).then(jsonResponse => {
            userId = jsonResponse.id;

            return fetch(`https://api.spotify.com/v1/users/${userId}/playlists`,
                {
                    headers: headers,
                    method: 'POST',
                    body: JSON.stringify({ name: name })
                }).then(response => response.json()
                ).then(jsonResponse => {
                    const playlistId = jsonResponse.id;
                    return fetch(`https://api.spotify.com/v1/users/${userId}/playlists/${playlistId}/tracks`, {
                        headers: headers,
                        method: 'POST',
                        body: JSON.stringify({ uris: trackURIs })
                    });
                });
        });

    }

}

export default Spotify;

Hello!

Three things:

  1. Always catch errors in promises and print them to the console for debugging. You can do this by providing a second argument to then() (Promise.prototype.then() - JavaScript | MDN) or by using catch() method (Promise.prototype.catch() - JavaScript | MDN).
  2. Always check the ok property of the fetch result (Response.ok - Web APIs | MDN) because you might get a server error. In this case, the promise resolves without error, but the ok property is set to false.
  3. Try adding the Content-Type: application/json header to your POST requests.