Jamming - search not working

Hi, I got to about step 95 of the Jamming project and when I click the search button I am not receiving any data from Spotify and no results show up when I search for a song. Could someone look over my code and tell me what I am possibly doing wrong?

Sotify.js

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

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

        // check for an access token match
        const accessToeknMatch = window.location.href.match(/access_token=([^&]*)/);
        const expiresInMatch = window.location.href.match(/expires_in=([^&]*)/);

        if (accessToeknMatch && expiresInMatch) {
            accessToken = accessToeknMatch[1];
            const expiresIn = Number(expiresInMatch[1]);
            // This clears the parameters, allowing to grab a new access token when it expires
            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.artist[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`,
            {
                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;

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;
    }
    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})
    })
    console.log('working');
  }

  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;

SearchBar.js

import React from "react";

import './SearchBar.css';

class SearchBar extends React.Component {

    constructor(props) {
        super(props);

        this.stae = {
            term: ''
        }

        this.search = this.search.bind(this);
        this.handleTermChange = this.handleTermChange.bind(this);
    }

    search() {
        this.props.onSearch(this.state.term);
    }

    handleTermChange(e) {
        this.setState({ term: e.target.value });
    }

    render() {
        return (
        <div className="SearchBar">
            <input onChange={this.handleTermChange} placeholder="Enter A Song, Album, or Artist" />
            <button onClick={this.search} className="SearchButton">SEARCH</button>
        </div>
        )
    }
}

export default SearchBar;

Playlist.js

import React from "react";

import './Playlist.css';

import Tracklist from "../Tracklist/Tracklist";

class Playlist extends React.Component {

    constructor(props) {
        super(props);

        this.handleNameChange = this.handleNameChange.bind(this);
    }

    handleNameChange(e) {
        this.props.onNameChange(e.target.value);
    }

    render() {
        return (
            <div className="Playlist">
                <input defaultValue={"New Playlist"} onChange={this.handleNameChange}/>
                <Tracklist tracks={this.props.playlistTracks}
                           onRemove={this.props.onRemove}
                           isRemoval={true} />
                <button className="Playlist-save" onClick={this.props.onSave}>SAVE TO SPOTIFY</button>
            </div>
        )
    }
}

export default Playlist;

Tracklist.js

import React from "react";

import './Tracklist.css';
import Track from "../Track/Track";

class Tracklist extends React.Component {
    render() {
        return (
            <div className="TrackList">
                {
                     this.props.tracks.map(track => {
                        return <Track track={track}
                                      key={track.id}
                                      onAdd={this.props.onAdd}
                                      onRemove={this.props.onRemove}
                                      isRemoval={this.props.isRemoval} />
                    })
                }
            </div>
        )
    }
}

export default Tracklist;

Track.js

import React from "react";

import './Track.css';

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


        this.addTrack = this.addTrack.bind(this);
        this.removeTrack = this.removeTrack.bind(this);
    }

   renderAction() {
        if (this.props.isRemoval) {
            return <button className="Track-action" onClick={this.removeTrack}>-</button>
        } else {
            return <button className="Track-action" onClick={this.addTrack}>+</button>
        }
    }

    addTrack() {
        this.props.onAdd(this.props.track);
    }

    removeTrack() {
       this.props.onRemove(this.props.track); 
    }

    render() {
        return (
            <div className="Track">
                <div className="Track-information">
                    <h3>{this.props.track.name}</h3>
                    <p>{this.props.track.artist} | {this.props.track.album}</p>
                </div>
               {this.renderAction()}
            </div>
        )
    }
}

export default Track;

SearchResults.js

import React from "react";

import './SearchResults.css';

import Tracklist from "../Tracklist/Tracklist";

class SearchResults extends React.Component {
    render() {
        return (
            <div className="SearchResults">
                <h2>Results</h2>
                <Tracklist tracks={this.props.searchResults}
                           onAdd={this.props.onAdd}
                           isRemoval={false} />
            </div>
        )
    }
}

export default SearchResults;

have the same problem. I followed the “Get Unstuck” instructions code by code but it still didn’t work. You can try to put onClick on one of the components as suggested by the Youtube comments, but it still didn’t work for me. Skipped the project to continue with the course and put Jammming on hold as it wasted a lot of time to debug. Sometimes the answer might not be given to you immediately, so try to continue the course and who knows, the answer my be taught in the newer courses! Cheers :wink:

In the below code, the artist property is actually found at track.artists[0].name

Once you fix that I believe you should find get a result.

In your search bar component it appears a typo may have gotten in there, with this.stae instead of this.state! Not totally sure if this is necessarily the reason for the issue, but given the SearchBar state property term is the one used for the search itself it’s possibly that!

1 Like