Build a Product Showcase - Build a Product Showcase

Tell us what’s happening:

Hi all

test 39 - 42 fail, which are the filter button tests
I can see the filters working in the preview.

i tried the solutions mentioned in other similar questions, like
I’ve tried getting the buttons with a querySelectorAll and getting them separately.
I’ve used incognito mode, and reseting the task and repasting my code

but nothing seams to solve it

any help or pointers will be gratefully received

Your code so far

<!-- file: index.html -->

/* file: styles.css */

/* file: index.ts */
interface Item {
  type: "book" | "electronics" | "clothing";
  id: string;
  price: number;
}

interface Book extends Item {
  type: "book";
  title: string;
  author: string;
}

interface Electronics extends Item {
  type: "electronics";
  item: string;
  model: string;
  warranty?: number;
}

interface Clothing extends Item {
  type: "clothing";
  item: string;
  brand: string;
  size?: "S" | "M" | "L";
}

type Product = Book | Electronics | Clothing;

class Collection <T> {
  items : T[]
  constructor (items: T[]) {
    this.items = items
  }

  getAll(): T[] {
    return this.items
  }

  filter(callback: Function) {
    return this.items.filter((item: T) => callback(item))
  }
}

function isBook(item: Item): item is Book {
  return item.type === "book"
}

function isElectronics(item: Item): item is Electronics {
  return item.type === "electronics"
}

function isClothing(item: Item): item is Clothing {
  return item.type === "clothing"
}

function renderProduct (product: Product): string {
  const sterlingFormatter = new Intl.NumberFormat('en-GB', {
    style: 'currency',
    currency: 'GBP',
  })
  
  let HTMLStringArr = [`
  <div id="${product.id}" class="item">
  `]

  if (isBook(product)) {
    HTMLStringArr.push(`
      <p>Book: ${product.title} by ${product.author}</p>
    `)
  }
  else if (isElectronics(product)) {
    HTMLStringArr.push(`
      <p>Electronics: ${product.item} - ${product.model}${product.warranty ? ` - Warranty: ${product.warranty} year(s)` : ""}</p>
    `)
  }
  else if (isClothing(product)) {
    HTMLStringArr.push(`
      <p>Clothing: ${product.item} by ${product.brand}${product.size ? ` - Size ${product.size}` : ""}</p>
    `)
  }
  else {
    throw new Error(`Unknown product type: ${JSON.stringify(product)}`)
  }

  HTMLStringArr.push(`<p class="price">${sterlingFormatter.format(product.price)}</p></div>
  `)

  return HTMLStringArr.join("")
}

const books: Book[] = [
  { id: "b1", type: "book", price: 12.99, title: "The Hobbit", author: "J.R.R. Tolkien" },
  { id: "b2", type: "book", price: 9.5, title: "1984", author: "George Orwell" },
  { id: "b3", type: "book", price: 15, title: "Dune", author: "Frank Herbert" },
  { id: "b4", type: "book", price: 8.75, title: "Fahrenheit 451", author: "Ray Bradbury" },
];

const electronics: Electronics[] = [
  { id: "e1", type: "electronics", price: 799, item: "Laptop", model: "X1-Carbon", warranty: 24 },
  { id: "e2", type: "electronics", price: 149, item: "Headphones", model: "QuietComfort", warranty: 1  },
  { id: "e3", type: "electronics", price: 999, item: "Smartphone", model: "Pixel 9", warranty: 6 },
  { id: "e4", type: "electronics", price: 249, item: "Tablet", model: "MiniPad 3" },
];

const clothing: Clothing[] = [
  { id: "c1", type: "clothing", price: 45, item: "T-Shirt", brand: "Uniqlo", size: "M" },
  { id: "c2", type: "clothing", price: 89, item: "Jeans", brand: "Levi's", size: "L" },
  { id: "c3", type: "clothing", price: 120, item: "Jacket", brand: "The North Face" },
  { id: "c4", type: "clothing", price: 25, item: "Socks", brand: "Nike", size: "S" },
];

const allItems: Product[] = [...books, ...electronics, ...clothing];

const products = new Collection<Product>(allItems)

const outputElement: HTMLElement = document.getElementById("output")!

// const buttonElements: NodeListOf<HTMLButtonElement> = document.querySelectorAll("button")

function isButtonElement(button: unknown): button is HTMLButtonElement {
  return button instanceof HTMLButtonElement
}

// buttonElements.forEach(button => {
//   button.addEventListener("click", (e) => {
//     if (isButtonElement(e.currentTarget)){
//       let id: string = e.currentTarget.id
//       if (id === "books") id = "book"
//       showProducts(id)
//     }
//   })
// })

const allButton = document.querySelector("#all") as HTMLButtonElement
const booksButton = document.querySelector("#books") as HTMLButtonElement
const electronicsButton = document.querySelector("#electronics") as HTMLButtonElement
const clothingButton = document.querySelector("#clothing") as HTMLButtonElement

allButton.addEventListener("click", (e) => {
  if (isButtonElement(e.currentTarget)){
    showProducts("all")
  }
})
booksButton.addEventListener("click", (e) => {
  if (isButtonElement(e.currentTarget)){
    showProducts("book")
  }
})
electronicsButton.addEventListener("click", (e) => {
  if (isButtonElement(e.currentTarget)){
    showProducts("electronics")
  }
})
clothingButton.addEventListener("click", (e) => {
  if (isButtonElement(e.currentTarget)){
    showProducts("clothing")
  }
})

function showProducts(filterBy: string = "all"): void {
  let productsToRender: Product[]

  if (filterBy === "all" || filterBy === undefined) {
    productsToRender = products.getAll()
  }
  else {
    productsToRender = products.getAll().filter((product: Product) => product.type === filterBy)
  }

  outputElement.innerHTML = productsToRender.map(product => renderProduct(product)).join("")
}

document.addEventListener("DOMContentLoaded", (event) => {
  showProducts()
});

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36

Challenge Information:

Build a Product Showcase - Build a Product Showcase

GitHub Link: freeCodeCamp/curriculum/challenges/english/blocks/lab-product-showcase/696920c0c98a1ed58eb86293.md at main · freeCodeCamp/freeCodeCamp · GitHub

I’ve solved it, by renaming my product arrays to booksItems rather than just books, electronics to electronicsItems and clothing to clothingItems

For some reason, this was making the tests fail!
If someone could explain whether it was my error or something the tests were picking up, I would appreciate the explanation


interface Item {

  type: "book" | "electronics" | "clothing";

  id: string;

  price: number;

}




interface Book extends Item {

type: "book";

  title: string;

  author: string;

}




interface Electronics extends Item {

type: "electronics";

  item: string;

  model: string;

  warranty?: number;

}




interface Clothing extends Item {

type: "clothing";

  item: string;

  brand: string;

  size?: "S" | "M" | "L";

}




type Product = Book | Electronics | Clothing;




class Collection <T> {

  items : T[]

constructor (items: T[]) {

this.items = items

  }




  getAll(): T[] {

return this.items

  }




  filter(callback: Function) {

return this.items.filter((item: T) => callback(item))

  }

}




function isBook(item: Item): item is Book {

return item.type === "book"

}




function isElectronics(item: Item): item is Electronics {

return item.type === "electronics"

}




function isClothing(item: Item): item is Clothing {

return item.type === "clothing"

}




function renderProduct (product: Product): string {

const sterlingFormatter = new Intl.NumberFormat('en-GB', {

    style: 'currency',

    currency: 'GBP',

  })

let HTMLStringArr = [`

  <div id="${product.id}" class="item">

  `]




if (isBook(product)) {

HTMLStringArr.push(`

      <p>Book: ${product.title} by ${product.author}</p>

    `)

  }

else if (isElectronics(product)) {

HTMLStringArr.push(`

      <p>Electronics: ${product.item} - ${product.model}${product.warranty ? ` - Warranty: ${product.warranty} year(s)` : ""}</p>

    `)

  }

else if (isClothing(product)) {

HTMLStringArr.push(`

      <p>Clothing: ${product.item} by ${product.brand}${product.size ? ` - Size ${product.size}` : ""}</p>

    `)

  }

else {

throw new Error(`Unknown product type: ${JSON.stringify(product)}`)

  }




HTMLStringArr.push(`<p class="price">${sterlingFormatter.format(product.price)}</p></div>

  `)




return HTMLStringArr.join("")

}




const booksItems: Book[] = [

  { id: "b1", type: "book", price: 12.99, title: "The Hobbit", author: "J.R.R. Tolkien" },

  { id: "b2", type: "book", price: 9.5, title: "1984", author: "George Orwell" },

  { id: "b3", type: "book", price: 15, title: "Dune", author: "Frank Herbert" },

  { id: "b4", type: "book", price: 8.75, title: "Fahrenheit 451", author: "Ray Bradbury" },

];




const electronicsItems: Electronics[] = [

  { id: "e1", type: "electronics", price: 799, item: "Laptop", model: "X1-Carbon", warranty: 24 },

  { id: "e2", type: "electronics", price: 149, item: "Headphones", model: "QuietComfort", warranty: 1  },

  { id: "e3", type: "electronics", price: 999, item: "Smartphone", model: "Pixel 9", warranty: 6 },

  { id: "e4", type: "electronics", price: 249, item: "Tablet", model: "MiniPad 3" },

];




const clothingItems: Clothing[] = [

  { id: "c1", type: "clothing", price: 45, item: "T-Shirt", brand: "Uniqlo", size: "M" },

  { id: "c2", type: "clothing", price: 89, item: "Jeans", brand: "Levi's", size: "L" },

  { id: "c3", type: "clothing", price: 120, item: "Jacket", brand: "The North Face" },

  { id: "c4", type: "clothing", price: 25, item: "Socks", brand: "Nike", size: "S" },

];




const allItems: Product[] = [...booksItems, ...electronicsItems, ...clothingItems];




const products = new Collection<Product>(allItems)




const outputElement: HTMLElement = document.getElementById("output")!




function isButtonElement(button: unknown): button is HTMLButtonElement {

return button instanceof HTMLButtonElement

}




const buttonsContainer = document.querySelector(".buttons") as HTMLElement;




buttonsContainer.addEventListener("click", (e) => {

if (isButtonElement(e.target)) {

let id = e.target.id;

if (id === "books") id = "book";

    showProducts(id);

  }

});




function showProducts(filterBy: string = "all"): void {

let productsToRender: Product[]




if (filterBy === "all" || filterBy === undefined) {

    productsToRender = products.getAll()

  }

else {

    productsToRender = products.filter((product: Product) => product.type === filterBy)

  }




  outputElement.innerHTML = productsToRender.map(product => renderProduct(product)).join("")

}




document.addEventListener("DOMContentLoaded", (event) => {

  showProducts()

});