Hello everyone, I had just reached step 95 on the Jamming project in the Full Stack/Front end skill path, however, I have reached an issue that I’m unable to resolve. The first one is that the search button at first did not return any results I then tried to add an “onClick” attribute to the button in the searchBar.js file which then returned an error.
App.js
import React from 'react';
import { SearchBar } from '../SearchBar/SearchBar';
import { SearchResults } from '../SearchResults/SearchResults';
import { Playlist } from '../Playlist/Playlist';
import './App.css';
import Spotify from '../../util/Spotify';
export default class App extends React.Component {
constructor (props) {
super(props);
this.state = {
searchResults: [],
playlistName: 'My playlist1',
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) {
if (this.state.playlistTracks.find(playlistTrack => track.id === playlistTrack.id)) {
return;
} else {
let playlistTracks = [...this.state.playlistTracks, track]
this.setState( playlistTracks)
}
}
removeTrack (track) {
if (this.state.playlistTracks.find(playlistTrack => track.id === playlistTrack.id)){
const playlistTracks = this.state.playlistTracks.splice(track)
this.setState({
playlistTracks
})
}
}
updatePlaylistName (name) {
this.setState(
{
playlistName: name
}
)
}
savePlaylist () {
let trackURIs = this.state.playlistTracks.map(playlistTrack => playlistTrack.uri)
Spotify.savePlaylist(this.state.playlistName, trackURIs).then(() => {
this.setState({
playlistName: 'New Playlist',
playlistTracks: []
})
})
}
search (searchTerm){
Spotify.search(searchTerm)
.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>
)
}
}
Spotify.js
let userAccessToken ;
const clientID = '0f1cc4ac9f46414d8c00196d8417fd63';
const redirectURI = 'http://localhost:3000/'
const Spotify = {
getAccessToken () {
if (userAccessToken) {
return userAccessToken ;
}
// check for an access token
const userAccessTokenMatch = window.location.href.match(/access_token=([^&]*)/);
const expiresInMatch = window.location.href.match(/expires_in=([^&*])/);
if (userAccessTokenMatch && expiresInMatch) {
userAccessToken = userAccessTokenMatch[1]
const expiresIn = Number(expiresInMatch[1])
// This clears the parameters , allowing us to grab a new access token when it expires.
window.setTimeout(() => userAccessToken = '',expiresIn * 1000);
window.history.pushState('Access Token', null, '/');
} else {
window.location = `https://accounts.4spotify.com/authorize?client_id=${clientID}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirectURI}`
}
},
search (userSearchTerm) {
fetch(`https://api.spotify.com/v1/search?type=track&q=${userSearchTerm}`,{
headers: {
Authorization: `Bearer ${userAccessToken}`
}
})
.then((response) => {
console.log(response)
if (!response.ok){
throw Error('could not fetch the data for that resource')
}
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
}));
})
.catch((error) => {
console.log(error.message);
})
},
// Created method to save plaist unto Spotify using fetch()
savePlaylist (playlistName,trackURIs) {
if (!playlistName || trackURIs.length ) {
return;
}
const accessToken = Spotify.getAccessToken();
const headers = { Authorization: `Bearer ${accessToken}`};
let usersID;
fetch('https://api.spotify.com/v1/me', {headers: headers,})
.then((response) => {
console.log(response)
if (!response.ok){
throw Error('could not fetch the data for that resource')
}
response.json()
})
.then(jsonResponse => {
usersID = jsonResponse.id
return fetch(`https://api.spotify.com/v1/users/${usersID}/playlists`,
{ header: headers,
method: 'POST',
body: JSON.stringify({name: playlistName })
})
})
.then((response) => {
if (!response.ok){
throw Error('Could not fetch the data for that resource')
}
response.json()
})
.then(jsonResponse => {
const playlistID = jsonResponse.id;
return fetch(`https://api.spotify.com/v1/users/${usersID}/playlist/${playlistID}/tracks`,{
headers: headers,
method: 'POST',
body: JSON.stringify({uris: trackURIs})
});
})
.catch((err) => {
console.log(err.message);
})
}
}
export default Spotify
SearchBar.js
import React from 'react';
import './SearchBar.css';
export class SearchBar extends React.Component {
constructor(props) {
super(props);
this.search = this.search.bind(this)
this.handleTermChange = this.handleTermChange.bind(this)
}
handleTermChange (e) {
const handleTerm = e.target.value;
this.setState({
searchTerm: handleTerm
});
}
search () {
this.props.onSearch(this.state.searchTerm)
}
render () {
return (
<div className="SearchBar">
<input placeholder="Enter A Song, Album, or Artist"
onChange={this.handleTermChange} />
<button className="SearchButton" onClick={this.search}>SEARCH</button>
</div>
)
}
};
SearchResults.js
import React from 'react';
import { Tracklist } from '../Tracklist/Tracklist';
import './SearchResults.css';
export 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>
)
}
};