Build a Flashcard Quiz App - Build a Flashcard Quiz App

Tell us what’s happening:

I am currently attempting the build a flashcard app and my app isn’t passing test 8: The delete button should remove a flashcard element from the currentCards collection. The best idea I have is because I am using localStorage to save the user’s data and load it when launched but I don’t know why that would make the test fail.

Your code so far

<!-- file: index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Deki Deck</title>
    <link rel="stylesheet" href="styles.css" />
    <link href="https://fonts.googleapis.com/css2?family=Righteous&family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
  </head>
  <body>
    <header class="flex align-center justify-between section-width lr-padding">
      <a href="#"><h1 id="logo" class="flex column align-center" aria-hidden>Deki Deck</h1></a>
      <a href="#" id="user-avatar-link"><img id="user-avatar" src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fcdn.pixabay.com%2Fphoto%2F2011%2F12%2F13%2F14%2F28%2Fearth-11009_1280.jpg&f=1&nofb=1&ipt=597a537adaa5745ef46f8981728f8a0f06162c4ad557a8fd12815ac43bfbb06f" alt="User profile picture" /></a>
    </header>
    <main class="section-width flex align-center column center justify-between padding">
      <div id="flash-card-container" class="flex align-center column justify-between padding container">
        <h2>Flash Card Viewer</h2>
        <div id="flashcard" class="flex align-center justify-center padding card">
          <div id="card-front"></div>
          <div id="card-back" class="hidden"></div>
        </div>
      </div>
      <div id="card-manager-container" class="flex align-center column center justify-between padding container">
        <h2>Manage Cards</h2>
        <form id="entry-form" class="card padding flex column justify-center align-center">
          <h3>Add New Card</h3>
          <label class="newcard-label font-bold" for="front-text">Front</label>
          <textarea id="front-text" class="newcard-input"></textarea>
          <label class="newcard-label font-bold" for="back-text">Back</label>
          <textarea id="back-text" class="newcard-input"></textarea>
          <button id="save-btn" class="button font-bold" type="submit">Save New Flash Card</button>
        </form>
        <div id="allcards-container" class="card padding">
          <h3>All Cards</h3>
          <div id="all-cards" class="card padding flex column justify-center align-center">
          </div>
        </div>
        <button id="delete-btn" class="button font-bold">Delete Current Flash Card</button>
      </div>
    </main>
    <footer class="flex column align-center section-width center padding justify-between">
      <div id="links-container" class="flex column section-width">
        <div id="about-us-container">
          <h2>About Us</h2>
          <ul class="font-normal">
            <li><a href="#">What is Deki Deck?</a></li>
            <li><a href="#">Why did I make Deki Deck?</a></li>
          </ul>
        </div>
        <div id="resources-container">
          <h2>Resources</h2>
          <ul class="font-normal">
            <li><a href="#">Frequently Asked Questions (FAQ)</a></li>
            <li><a href="#">Totally Legit Deki Decks</a></li>
            <li><a href="#">How to use Deki Deck</a></li>
          </ul>
        </div>
        <div id="contact-us-container">
          <h2>Contact Us</h2>
          <ul class="font-normal">
            <li>Email: <a href="#" class="contact-link">totallylegit@email.com</a></li>
            <li>Cell: <a href="#" class="contact-link">+101 423 13223 345</a></li>
            <li>Phone: <a href="#">+101 011 12143 233</a></li>
          </ul>
        </div>
      </div> 
      <p>Deki Deck is a product made purely for educational purposes and is not an actual flashcard program.</p>      
    </footer>
    <script src="index.ts"></script>
  </body>
</html>
/* file: index.ts */
interface FlashCard {
  questionText: string;
  questionAnswer: string;
}

const STORAGE_KEY = "saved_cards";

let currentCards: FlashCard[] = [];
let currentCard = currentCards.length - 1;

function loadCards(): FlashCard[] {
  try {
    const saved = localStorage.getItem(STORAGE_KEY);
    if (saved) {
      return JSON.parse(saved);
    }
  } catch (error) {
    console.log("Failed to load flash cards:", error);
  }
  return [];
}

function selectCard(index: number) {
  currentCard = index;
  handleCards();
}

function saveCards() {
  try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(currentCards));
    } catch (error) {
      console.log("Failed to save flash card data:", error);
    }
}

function handleCards() {
  if (currentCard === -1) {
    currentCard = currentCards.length - 1;
  } else if (currentCard >= currentCards.length) {
    currentCard = currentCards.length - 1;
  }

  if (currentCards.length >= 1) {
    if (cardFront && cardBack) {
      cardFront.textContent = currentCards[currentCard].questionText;
      cardBack.textContent = currentCards[currentCard].questionAnswer
    }

    if (allCards) {
      allCards.innerHTML = currentCards.map((card, index) => `<button data-index="${index}" class="button">${card.questionText.length > 20 ? `${card.questionText.slice(0, 21)}...` : card.questionText}</button>`).join("");
    }
  } else { 
    if (cardFront && cardBack && allCards) {
      cardFront.textContent = "";
      cardBack.textContent = "";
      allCards.innerHTML = "";
    }
  }
}

const saveBtn = document.querySelector<HTMLInputElement>("#save-btn");
const deleteBtn = document.querySelector<HTMLButtonElement>("#delete-btn");
const flashcard = document.querySelector<HTMLElement>("#flashcard");
const cardFront = document.querySelector<HTMLElement>("#card-front");
const cardBack = document.querySelector<HTMLElement>("#card-back");
const frontText = document.querySelector<HTMLTextAreaElement>("#front-text");
const backText = document.querySelector<HTMLTextAreaElement>("#back-text");
const allCards = document.querySelector<HTMLElement>("#all-cards");


class InvalidUserInputError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'InvalidUserInputError';
  }
}

document.addEventListener("DOMContentLoaded", () => {
  currentCards = loadCards();
  handleCards();
});

if (saveBtn) {
  saveBtn.addEventListener("click", (e) => {
    e.preventDefault();
    try {
      if (frontText && backText) {
        if (frontText.value === "" || backText.value === "") {
          throw new InvalidUserInputError("Front or Back Text Missing");
        }

        currentCards = [...currentCards, {
          questionText: frontText.value,
          questionAnswer: backText.value,
        }];

        frontText.value = "";
        backText.value = "";
        
        saveCards();
        handleCards();
      }
    } catch (error) {
        if (error instanceof InvalidUserInputError) {
          alert("The Front and Back of the flash card should both have values.");
        } else {
          console.error("Unexpected error:", error);
        }
    }
  })
}

if (deleteBtn) {
  deleteBtn.addEventListener("click", () => {
    if (currentCards.length >= 1) {
      currentCards = currentCards.filter((_, index) => index !== currentCard);
      if (flashcard) {
        flashcard.classList.toggle("flipped");
      }

      if (currentCards.length === 0) {
        currentCard = -1;
      } else if (currentCard >= currentCards.length) {
        currentCard = currentCards.length - 1;
      }

      saveCards();
      handleCards();
    }
  })
}

if (allCards) {
  allCards.addEventListener("click", (e) => {
    const button = (e.target as HTMLElement).closest("button");
    if (button) {
      const index = parseInt(button.getAttribute("data-index") || "0");
      selectCard(index);
    }
  });
}

if (flashcard && cardFront && cardBack) {
  flashcard.addEventListener("click", () => flashcard.classList.add("flipped"));

    flashcard.addEventListener("mouseenter", () => {
      if (flashcard.classList.contains("flipped")) {
        cardBack.classList.toggle("hidden");
        cardFront.classList.toggle("hidden");
      }
    });

    flashcard.addEventListener("mouseleave", () => {
      if (flashcard.classList.contains("flipped")) {
        cardBack.classList.toggle("hidden");
        cardFront.classList.toggle("hidden");
      }
    });
  }

/* file: styles.css */
/* General Styling */
:root {
  /* Color Variables */
  --main-background : #090912;
  --flash-card-container-background: #121222;
  --delete-button-background: #CC0066;
  --main-text: #DFDFEF;
  --logo-text: #0066CC;
  --footer-text: #BFBFCF;
  --footer-link-hover-text: #BFBFDF;
  --main-header-text: #006BCC;
  --secondary-header-text: #007ACC;
  --button-text: #09091F;
  --main-border-color: #002B5C;
  --secondary-border-color: #003DA5;
  --delete-button-border-color: #A5003D;
  /* Size Variables */
  --header-height: 3rem;
  --footer-height: 20rem;
  --main-section-height: 68rem;
  --container-width: 100%;
  --flashcard-container-height: 24rem;
  --card-width: 95%;
  --flashcard-height: 20rem;
  --manage-container-height: 42.5rem;
  --newcard-container-height: 20rem;
  --allcards-container-height: 15rem;
  --newcard-input-width: 90%;
  --newcard-input-height: 4rem;
  --border-main-size: 0.2rem;
  --border-secondary-size: 0.15rem;
  --user-avatar-size: 70%;
  --logo-star-size: .7rem;
  --lr-padding: 0.5rem;
  --padding: 0.5rem;
  --logo-font-size: 1.2rem;
  --footer-heading-size: 1.1rem;
  --footer-text-size: .8rem;
  --main-section-text-size: 1rem;
  --main-header-text-size: 1.4rem;
  --secondary-header-text-size: 1.1rem;
  --button-text-size: 0.85rem;
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 17.6px;
}

body {
  background-color: var(--main-background);
  color: var(--main-text);
  width: 100%;
  font-family: "Poppins", 'Arial Black', Gadget, sans-serif;
  position: relative;
}

.flex {
  display: flex;
}

.column {
  flex-direction: column;
}

.align-center {
  align-items: center;
}

.justify-between {
  justify-content: space-between;
}

.justify-center {
  justify-content: center;
}

.section-width {
  width: 100%;
}

.font-normal {
  font-weight: 500;
}

.font-bold {
  font-weight: 600;
}

.center {
  text-align: center;
}

.lr-padding {
  padding: 0 var(--lr-padding);
}

.padding {
  padding: var(--padding);
}

a {
  text-decoration: none;
  color: var(--text-color);
}

a:hover {
  color: var(--footer-link-hover-text);
}

ul {
  list-style: none;
}

.hidden {
  display: none;
}

/* Header Styling */
header {
  height: var(--header-height);
  border-bottom: var(--border-main-size) solid var(--main-border-color);
  position: sticky;
  top: 0;
  background-color: var(--main-background);
  z-index: 1;
}

#logo {
  font-family: 'Righteous', 'Arial Black', Gadget, sans-serif;
  font-size: var(--logo-font-size);
  font-weight: 400;
  color: var(--logo-text);
  line-height: .5
}

#logo:after {
  font-size: var(--logo-star-size);
  content: "★                                ☆";
  white-space: pre-wrap;
  display: block;
  line-height: 0;
}

#logo:before {
  font-size: var(--logo-star-size);
  content: "☆                            ★";
  white-space: pre-wrap;
  display: block;
  line-height: 0;
}

#user-avatar-link {
  display: inline-block;
  height: var(--user-avatar-size); 
}

#user-avatar {
  height: 100%;
  border-radius: 50%;
  border: var(--border-secondary-size) outset var(--secondary-border-color)
}

/* Main Section Styling */
main {
  height: var(--main-section-height);
  font-size: var(--main-section-text-size);
}

main h2 {
  color: var(--main-header-text);
  font-size: var(--main-header-text-size);
}

.container {
  background-color: var(--flash-card-container-background);
  width: var(--container-width);
  border-radius: .4rem;
}

.card {
  background-color: var(--main-background);
  border-radius: .6rem;
  width: var(--card-width);
}

#flash-card-container {
  height: var(--flashcard-container-height);
}

#flashcard {
  height: var(--flashcard-height);
  transition: transform 0.5s;
  transform-style: preserve-3d;
  word-break: break-all;
}

.flipped {
  transform: perspective(1000px) rotateY(180deg);
}

#card-back {
  transform: rotateY(180deg);
}

#flashcard:hover {
  cursor: pointer;
  transform: translateY(-.5rem);
}

#card-manager-container {
  height: var(--manage-container-height);
}

#entry-form {
  height: var(--newcard-container-height);
  overflow-y: auto;
  gap: .7rem;
}

.newcard-label {
  color: var(--secondary-header-text);
  font-size: var(--secondary-header-text-size);
}

.newcard-input {
  width: var(--newcard-input-width);
  height: var(--newcard-input-height);
  resize: vertical;
  border-radius: .8rem;
  padding: .3rem;
  font-size: var(--main-section-text-size);
  flex-shrink: 0;
}

#allcards-container {
  height: var(--allcards-container-height);
  overflow-y: auto;
}

.button {
  border-radius: 10rem;
  padding: .6rem;
  color: var(--button-text);
  font-size: var(--button-text-size);
  background-color: var(--main-header-text);
  border: var(--border-secondary-size) outset var(--secondary-header-text);
  margin: 0.1rem;
}

.button:hover {
  cursor: pointer;
  filter: brightness(1.2);
}

.button:focus {
  outline: var(--border-secondary-size) outset var(--main-text);
}

#delete-btn {
  background-color: var(--delete-button-background);
  border-color: var(--delete-button-border-color);
}

/* Footer Styling */
footer {
  color: var(--footer-text);
  height: var(--footer-height);
  border-top: var(--border-main-size) solid var(--main-border-color);
  font-size: var(--footer-text-size);
}

#links-container h2 {
  font-size: var(--footer-heading-size);
}

@media (min-width: 768px)  {
  :root {
    --footer-height: 9rem;
    --container-width: 60%;
    --main-section-height: 70rem;
    --manage-container-height: 44.5rem;
    --newcard-container-height: 22rem;

    --main-section-text-size: 1.2rem;
    --main-header-text-size: 1.8rem;
    --secondary-header-text-size: 1.4rem;
    --button-text-size: 0.95rem;
  }

  #links-container {
    flex-direction: row;
    justify-content: space-evenly;
    align-items: space-evenly;
  }
}

@media (min-width: 1024px) {
  :root {
    --footer-height: 9rem;
    --container-width: 60%;
    --main-section-height: 70rem;
    --manage-container-height: 44.5rem;
    --newcard-container-height: 22rem;

    --main-section-text-size: 1.2rem;
    --main-header-text-size: 1.8rem;
    --secondary-header-text-size: 1.4rem;
    --button-text-size: 0.95rem;
  }

  #links-container {
    flex-direction: row;
    justify-content: space-evenly;
    align-items: space-evenly;
  }
}

Your browser information:

User Agent is: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36

Challenge Information:

Build a Flashcard Quiz App - Build a Flashcard Quiz App

GitHub Link: freeCodeCamp/curriculum/challenges/english/blocks/lab-flashcard-quiz-app/69b868127999e97f1903f8e1.md at main · freeCodeCamp/freeCodeCamp · GitHub