Jamming - error when trying to save playlist - TypeError: Cannot read property 'then' of undefined

Hi everyone,

I am finally getting to the end of the jamming project, with the help of the forum I was able to correct some of the issues I had with my code but cannot figure out what this one means.Capture

Any pointers would be greatly appreciated. I have checked the forum and the project walkthrough but at this point, I am completely stuck.

const clientId = '';
const redirectUri = 'http://localhost:3000/';
let accessToken;

const Spotify = {
  getAccessToken(){
    if(accessToken){
      return accessToken;
    }

    // check for access 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[1]);

      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 = 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 => {
      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();
    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`,
    {
      hearders: 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;

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;
  }
  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;

Hello, @aurore, and welcome to the forums!

When you see a TypeError: Cannot read property ‘whatever’ of undefined, the place to start looking is where ‘whatever’ is attached to should have been defined. In this case, ‘then’ is being called on something that is undefined. The something is the return value of Spotify.savePlaylist(). So, we need to look at the savePlaylist() function in the Spotify component. I see a typo in that function. If you need a hint, try looking for the word, ‘hearders’. :wink:

1 Like

Thank you so much @midlindner, I feel a little bit silly now ;-).

1 Like