Jamming Project: I can't get the album data to render on my page using map

I’ve been trying to get the album cover art to replace the objects that are rendered on the page meant for the album image to be placed in. I have been trying to figure out the json path name for example data.album.name or album.image but I can’t seem to figure it out. I ran the API calls using Insomnia and I get the same data as shown in the example page from the how-to documentation from Spotify, but I can’t get the data to render on the page. I’m not sure what I’m doing wrong, any good hints or resource that can be provided will be appreciated. I been stuck on this for the past 10 hours. I’ve included a link to the gist for the main files and here is the tree structure of my main files.
└── mySpotifyModule
├── node_modules
├── package.json
├── package-lock.json
├── public
│ ├── index.html
│ └── spotify-bg.png
└── src
├── App
│ ├── App.css
│ └── App.js
├── index.css
├── index.js
├── Play
│ └── Playlist.js
├── script.js
├── Search
│ ├── SearchBar.css
│ ├── SearchBar.js
│ └── SearchResults.js
├── styles.css
└── Track
├── Track.js
└── Tracklist.js

App.js

import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";
import { Container, InputGroup, FormControl, Button, Card, Row } from "react-bootstrap";
import { useState, useEffect } from "react";

const CLIENT_ID = '684f2f7c27fc4e6eac20d56f7b4da9fe'
const CLIENT_SECRET = '256582d4f9d04a7f82631a7ec7cf5945'

function App() {
  const [searchInput, setSearchInput] = useState("");
  const [accessToken, setAccessToken] = useState("");
  const [albums, setAlbums] = useState([]); //Taylor Swift

  useEffect(() => {
    // API Access Token
    var authParameters = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      body: 'grant_type=client_credentials&client_id=' + CLIENT_ID + '&client_secret=' + CLIENT_SECRET
    }
    fetch('https:///accounts.spotify.com/api/token', authParameters)
      .then(results => results.json())
      .then(data => setAccessToken(data.access_token))
  }, [])

  // Search
  async function search() {
    console.log("Search for " + searchInput); //Taylor Swift

    var searchParameters = {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + accessToken
      }
    }
    var artistID = await fetch('https://api.spotify.com/v1/search?q=' + searchInput + '&type=artist', searchParameters)
      .then(response => response.json())
      .then(data => data.artists.items[0].id)

    console.log("Artist ID is " + artistID);
    // Get request with Artist ID grab all the albums from that artist
    var returnedAlbums = await fetch('https://api.spotify.com/v1/artists/' + artistID + '/albums' + '?include_groups=album&market=US&limit=50', searchParameters)
      .then(response => response.json())
      .then(data => {
        console.log(data.items);
        setAlbums(data.items);
      });

    // Display all the albums
  }
  console.log(albums);
  return (
    <div className="App">
      <Container>
        <InputGroup className="mb-3" size="lg">
          <FormControl
            placeholder="Search for an artist"
            type="input"
            onKeyDown={event => {
              if (event.key === "Enter") {
                search();
              }
            }}
            onChange={event => setSearchInput(event.target.value)}
          />
          <Button onClick={() => { console.log("Clicked Button") }}>
            Search
          </Button>
        </InputGroup>
      </Container>
      <Container>
        <Row className="mx-2 row row-cols-4">
          {albums.map((album, i) => (
            <Card key={i}>
              <Card.Img src={album.images[0]} />
              <Card.Body>
                <Card.Title>Album Name Here</Card.Title>
              </Card.Body>
            </Card>
          ))}
        </Row>
      </Container>
    </div>
  );
}
export default App;

Index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Spotify Profile</title>
  </head>
  <body>
    <div id="root"></div>
    <div className="header">
    <section id="profile">
    <h2>Logged in as: <span id="displayName"></span></h2>
    <span id="avatar"></span>
    </div>
    <ul>
        <li>User ID: <span id="id"></span></li>
        <li>Email: <span id="email"></span></li>
        <li>Spotify URI: <a id="uri" href="#"></a></li>
        <li>Link: <a id="url" href="#"></a></li>
        <li>Profile Image: <span id="imgUrl"></span></li>
    </ul>
    </section>
    <script src="src/App/App.js"></script>
  </body>
</html>

package.json

{
  "name": "react",
  "version": "1.0.0",
  "description": "React example starter project",
  "keywords": [
    "react",
    "starter"
  ],
  "main": "src/index.js",
  "dependencies": {
    "allow-cors": "^1.0.0",
    "bootstrap": "^5.3.0",
    "cors": "^2.8.5",
    "loader-utils": "3.2.1",
    "nextjs-cors": "^2.1.2",
    "react": "^18.2.0",
    "react-bootstrap": "^2.8.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "row": "^0.0.1"
  },
  "devDependencies": {
    "@babel/runtime": "7.13.8",
    "@types/react-dom": "^18.2.6",
    "dotenv": "^16.3.1",
    "express": "^4.18.2",
    "npm-run-all": "^4.1.5",
    "typescript": "4.1.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "server": "node server",
    "dev": "run-p server start",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "author": "",
  "license": "ISC"
}

index.js

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import App from "./App/App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);

script.js

const clientId = "684f2f7c27fc4e6eac20d56f7b4da9fe"; 
const params = new URLSearchParams(window.location.search);
const code = params.get("code");
const accessToken = "BQDdu7TSgqbktAc0PhtubsQLrpuXRd60h2OhRHEQKECVoj-ILdJDzUEu3r6sDUXqqSdHZ5LBbii_LDp4nqvdNOeXdDmUCVajexl4TmsIiDuB2HLZm-g"

if (!code) {
    redirectToAuthCodeFlow(clientId);
} else {
    getAccessToken(clientId, code)
        .then(accessToken => fetchProfile(accessToken))
        .then(profile => populateUI(profile))
        .catch(err => console.error(err));
}

async function redirectToAuthCodeFlow(clientId) {
    const verifier = generateCodeVerifier(128);
    const challenge = await generateCodeChallenge(verifier);

    localStorage.setItem("verifier", verifier);

    const params = new URLSearchParams();
    params.append("client_id", clientId);
    params.append("response_type", "code");
    params.append("redirect_uri", "http://localhost:5173/callback");
    params.append("scope", "user-read-private user-read-email");
    params.append("code_challenge_method", "S256");
    params.append("code_challenge", challenge);

    document.location = `https://accounts.spotify.com/authorize?${params.toString()}`;
    }

    function generateCodeVerifier(length) {
    let text = '';
    let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    for (let i = 0; i < length; i++) 
        text += possible.charAt(Math.floor(Math.random() * possible.length));
    
    return text;
    }

    async function generateCodeChallenge(codeVerifier) {
    const data = new TextEncoder().encode(codeVerifier);
    const digest = await window.crypto.subtle.digest('SHA-256', data);

    return btoa(String.fromCharCode(...new Uint8Array(digest)))
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=+$/, '');
    }

    async function getAccessToken(clientId, code) {
    const verifier = localStorage.getItem("verifier");

    const params = new URLSearchParams();
    
    params.append("client_id", clientId);
    params.append("grant_type", "authorization_code");
    params.append("code", code);
    params.append("redirect_uri", "http://localhost:5173/callback");
    params.append("code_verifier", verifier);
    
    const result = await fetch("https://accounts.spotify.com/api/token", {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: params
    });

    const { access_token } = await result.json();

    return access_token;
    }

    async function fetchProfile(token) {
    const result = await fetch("https://api.spotify.com/v1/me", {
        method: "GET", 
        headers: 
            { 
                'Content-Type': 'application/json',
                'Authorization': 'Bearer '+ token
            }
    });

    return result.json();
    }

    function populateUI(profile) {
    // Update UI with profile data
    document.getElementById("displayName").innerText = profile.display_name;
    if (profile.images[0]) {
        const profileImage = new Image(200, 200);
        profileImage.src = profile.images[0].url;
        document.getElementById("avatar").appendChild(profileImage);
        document.getElementById("imgUrl").innerText = profile.images[0].url;
    }
    document.getElementById("id").innerText = profile.id;
    document.getElementById("email").innerText = profile.email;
    document.getElementById("uri").innerText = profile.uri;
    document.getElementById("uri").setAttribute("href", profile.external_urls.spotify);
    document.getElementById("url").innerText = profile.href;
    document.getElementById("url").setAttribute("href", profile.href);
}

Hey @rorschache00714 !

Do you have this code on GitHub by chance? If so, can you share the repo?

Michael

1 Like

Thank you I appreciate the help, but I figured it out, it was my CSS settings not allowing it to display correctly.
This is an example pic in my Github repo for my README.md that i’ll continue to update as the project grows.

Github Screenshot

1 Like