Skip to content

Instantly share code, notes, and snippets.

@hbar1st
Created April 15, 2026 15:13
Show Gist options
  • Select an option

  • Save hbar1st/f218ba822f066981aba735d93ff62eaa to your computer and use it in GitHub Desktop.

Select an option

Save hbar1st/f218ba822f066981aba735d93ff62eaa to your computer and use it in GitHub Desktop.
step-25 workshop to Build an fCC Authors Page
id 69df434b56d2e0faf1a7424c
title Step 25
challengeType 0
dashedName step-25

--description--

Now that your fCC Authors Page is fully functional, let's refactor it to improve its readability by using async and await instead of the promise chaining method then.

Recall that in order to use the await operator to wait for a function that returns a Promise, you need to wrap the function call in an async function (if it is not in the main body of a module).

Since your fetch call is not defined in either an asynchronous function nor in the main body of a module, you cannot use await before fixing that.

Wrap the fetch statement and the entire sequence of chained then and catch methods as a whole in a new asynchronous arrow function called initialFetch which takes no arguments.

An example of an async function declaration is:

const functionName = async () => {}

--before-all--

window.fetch = () => Promise.resolve({json: () => Promise.resolve([{ author: 'Whoever', image: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==', url: "http://not-a-real-url.nowhere/", bio: 'words go here' }])});

--hints--

initialFetch should be a function.

assert.isFunction(initialFetch)

You should use const to create an initialFetch function.

assert.match(code, /const\s+initialFetch\s*=\s*/)

initialFetch should be an async function.

assert.match(code, /const\s+initialFetch\s*=\s*async\s*/)

Your initialFetch function should not take any parameter.

assert.match(code, /const\s+initialFetch\s*=\s*async\s*\(\s*\)\s*/)

Your initialFetch function should use arrow syntax.

assert.match(code, /const\s+initialFetch\s*=\s*async\s*\(\s*\)\s*=>\s*/)

Your initialFetch function should not be empty.

assert.notMatch(code, /const\s+initialFetch\s*=\s*async\s*\(\s*\)\s*=>\s*\{\s*\}/)

--seed--

--seed-contents--

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>freeCodeCamp News Author Page</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <h1 class="title">freeCodeCamp News Author Page</h1>

    <main>
      <div id="author-container"></div>
      <button class="btn" id="load-more-btn">Load More Authors</button>
    </main>

    <script src="./script.js"></script>
  </body>
</html>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

:root {
  --main-bg-color: #1b1b32;
  --light-grey: #f5f6f7;
  --dark-purple: #5a01a7;
  --golden-yellow: #feac32;
}

body {
  background-color: var(--main-bg-color);
  text-align: center;
}

.title {
  color: var(--light-grey);
  margin: 20px 0;
}

#author-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.user-card {
  border-radius: 15px;
  width: 300px;
  height: 350px;
  background-color: var(--light-grey);
  margin: 20px;
}

.user-img {
  width: 150px;
  height: 150px;
  object-fit: cover;
}

.purple-divider {
  background-color: var(--dark-purple);
  width: 100%;
  height: 15px;
}

.author-name {
  margin: 10px;
}

.bio {
  margin: 20px;
}

.error-msg {
  color: var(--light-grey);
}

.btn {
  cursor: pointer;
  width: 200px;
  margin: 10px;
  color: var(--main-bg-color);
  font-size: 14px;
  background-color: var(--golden-yellow);
  background-image: linear-gradient(#fecc4c, #ffac33);
  border-color: var(--golden-yellow);
  border-width: 3px;
}
const authorContainer = document.getElementById('author-container');
const loadMoreBtn = document.getElementById('load-more-btn');

let startingIndex = 0;
let endingIndex = 8;
let authorDataArr = [];

--fcc-editable-region--

fetch('https://cdn.freecodecamp.org/curriculum/news-author-page/authors.json')
  .then((res) => res.json())
  .then((data) => {
    authorDataArr = data;
    displayAuthors(authorDataArr.slice(startingIndex, endingIndex));  
  })
  .catch((err) => {
   authorContainer.innerHTML = '<p class="error-msg">There was an error loading the authors</p>';
  });

--fcc-editable-region--

const initialFetch = () => {
  startingIndex += 8;
  endingIndex += 8;

  displayAuthors(authorDataArr.slice(startingIndex, endingIndex));
  if (authorDataArr.length <= endingIndex) {
    loadMoreBtn.disabled = true;
    loadMoreBtn.style.cursor = "not-allowed"
    loadMoreBtn.textContent = 'No more data to load';
  }
};

const displayAuthors = (authors) => {
  authors.forEach(({ author, image, url, bio }, index) => {
    authorContainer.innerHTML += `
    <div id="${index}" class="user-card">
      <h2 class="author-name">${author}</h2>
      <img class="user-img" src="${image}" alt="${author} avatar">
      <div class="purple-divider"></div>
      <p class="bio">${bio.length > 50 ? bio.slice(0, 50) + '...' : bio}</p>
      <a class="author-link" href="${url}" target="_blank">${author} author page</a>
    </div>
  `;
  });
};

loadMoreBtn.addEventListener('click', initialFetch);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment