Jamming project: error "Unhandled Rejection (TypeError): response.json is not a function" when trying to save playlist

Hello there,
I’m almost at the end of the project but I’ve got an error when I try to save the playlist.
I realized when the page loads and I try to add a song the page just reloads. When I try that again the song is added. Then when I try to save the playlist I get that error.
I believe something goes wrong when it tries to get the accessToken but the code seems fine to me.

Thats my Spotify.js

const clientID = "";  //Please add your ID key here
const redirectURI = "http://localhost:3000/";

let accessToken;

const Spotify = {
  getAccessToken() {
    if (accessToken) {
      return accessToken;
    }
    console.log(window.location.href);
    // check access token match
    const accessTokenMatch = window.location.href.match(/access_token=([^&]*)/);
    const expiresInMatch = window.location.href.match(/expires_in=([^&]*)/);
    console.log(accessTokenMatch);

    if (accessTokenMatch && expiresInMatch) {
      accessToken = accessTokenMatch[1];
      const expiresIn = Number(expiresInMatch[1]);

      //clear parmeters
      window.setTimeout(() => (accessToken = ""), expiresIn * 1000);
      window.history.pushState("Access Token", null, "/");

      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.href = accessUrl;

    }
  },

  search(term) {
    const accessToken = Spotify.getAccessToken();
    return fetch(`https://api.spotify.com/v1/search?type=track&q=${term}`, {
      headers: { Authorization: `Bearer ${accessToken}` },
    })
      .then((response) => response.json())
      .then((jsonResponse) => {
        if (!jsonResponse.tracks) {
          return [];
        }

        return jsonResponse.tracks.items.map((track) => {
          console.log(track);
          return {
            id: track.id,
            name: track.name,
            artists: track.artists[0].name,
            album: track.album.name,
            uri: track.uri,
          };
        });
      });
  },

  savePlaylist(name, trackUris) {
    if (!name || !trackUris.length) {
      return;
    }

    const accessToken = Spotify.getAccessToken();
    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;
        try {
          return (
            fetch(`https://api.spotify.com/v1/users/${userID}/playlists`),
            {
              headers: headers,
              method: "POST",
              body: JSON.stringify({ name: name }),
            }
          );
        } catch (e) {
          console.log(e);
        }
      })
      .then((response) => response.json())
      .then((jsonResponse) => {
        const playlistID = jsonResponse.id;
        return fetch(
          `https://api.spotify.com/v1/v1/playlists/${playlistID}/tracks`,
          {
            headers: headers,
            method: "POST",
            body: JSON.stringify({ uris: trackUris }),
          }
        );
      });
  },
};

export default Spotify;

and App.js

import React from "react";

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

import "./App.css";

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

    this.state = {
      searchResults: [],
      playlistName: "New 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 newPlaylist = this.state.playlistTracks;
    if (newPlaylist.find((playTrack) => playTrack.id === track.id)) {
      return;
    } else {
      newPlaylist.push(track);
    }
    this.setState({ playlistTracks: newPlaylist });
    console.log(this.state.playlistTracks);
  }

  removeTrack(track) {
    let playlist = this.state.playlistTracks;
    let newPlaylist = playlist.filter((playTrack) => playTrack.id !== track.id);
    this.setState({ playlistTracks: newPlaylist });
  }

  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;

Here’s the link to the entire project:

Thanks for your help!

I get the same issue.

I found the issue, after fetching the first time in the saveplaylist method i didn’t put a then between the jsonResponse and the second fetch.
After updating that no more issues.
Btw I guess th page has to reload the first time in order to reach the access URL.
I hope that might help you

savePlaylist(name, trackUris) {
    if (!name || !trackUris.length) {
      return;
    }

    const accessToken = Spotify.getAccessToken();
    const headers = {
      Authorization: `Bearer ${accessToken}`,
    };
    return fetch("https://api.spotify.com/v1/me", { headers: headers })
      .then((response) => response.json())
      .then((jsonResponse) => (userID = jsonResponse.id))

// THIS THEN WAS MISSING
      .then((userID) => {
        return fetch(`https://api.spotify.com/v1/users/${userID}/playlists`, {
          method: "POST",
          headers: headers,
          body: JSON.stringify({
            name: name,
          }),
        });
      })
      .then((response) => {
        return response.json();
      })
      .then((jsonResponse) => {
        const playlistID = jsonResponse.id;
        return fetch(
          `https://api.spotify.com/v1/playlists/${playlistID}/tracks`,
          {
            headers: headers,
            method: "POST",
            body: JSON.stringify({ uris: trackUris }),
          }
        );
      });
  },