So I’ve been at it for hours trying to get this to work (I’ve tried adding an onClick to the search but that didn’t fix anything) and going back to the video to redo the entire spotify.js but still no luck. Please help. I don’t get an error when trying the search just nothing happens.
As for the error when clicking save playlist it says TypeError: Cannot read property ‘then’ of undefined and refers me to savePlaylist method on App.js but I’ve also rewritten this intently following the video but no luck. Please help
Spotify.js
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]);
//Clear the parameters from the URL
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 ('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 React 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);
}
// step 42 add track
addTrack(track) {
let tracks = this.state.playlistTracks;
if(tracks.find(savedTrack => savedTrack.id === track.id))
{
return;
} else {
tracks.push(track);
this.setState({playlistTracks: tracks});
}
}
//step 49 remove track
removeTrack(track) {
let tracks = this.state.playlistTracks;
tracks = tracks.filter( currentTrack => currentTrack.id !== track.id);
this.setState({playlistTracks: tracks});
}
//Step 57 Update Name of Playlist
updatePlaylistName(name) {
this.setState({playlistName: name});
}
//Step 63 Save Your New Playlist
savePlaylist() {
const trackUris = this.state.playlistTracks.map(track => track.uri);
Spotify.savePlaylist(this.state.playlistName, trackUris).then(() => {
this.setState({
playlistName: 'New Playlist',
playlistTracks: []
})
})
}
//Update Search Results of User
search(term) {
Spotify.search(term).then(searchResults => {
this.setState({searchResults: searchResults})
})
}
//Render Function
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.state = {
term: ''
}
this.search = this.search.bind(this);
this.handleTermChange = this.handleTermChange.bind(this);
}
search() {
this.props.onSearch(this.state.term);
}
handleTermChange(event) {
this.setState({term: event.target.value});
}
render() {
return (
<div className="SearchBar">
<input onChange={this.handleTermChange}
placeholder="Enter A Song, Album, or Artist"
/>
<button 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(event) {
this.props.onNameChange(event.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 SearchResults from '../SearchResults/SearchResults';
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
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;