<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>Shopping list</title>
    <link rel="stylesheet" href="/style.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/js/all.min.js"
        integrity="sha512-naukR7I+Nk6gp7p5TMA4ycgfxaZBJ7MO5iC3Fp6ySQyKFHOGfpkSZkYVWV5R7u7cfAicxanwYQ5D1e17EfJcMA=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>

<body>

    <div class="container">
        <h2>My Shopping list 📃 </h2>
        <input name="items" type="text" id="search" placeholder="Enter the items">
        <div class="results"></div>
        <div class="my-items"></div>
    </div>
</body>

</html>
body {
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
    Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}

.container {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  margin: 1rem 0;
}

input[type='text'] {
  padding: 0.4rem;
  width: 15%;
  outline: none;
}

.results {
  border: 1px solid black;
  width: 16%;
  display: none;
  position: relative;
  background-color: #f0f0f0;
  z-index: 1;
}

.show-results {
  display: block;
}

.results p {
  margin: 0.5rem;
  padding: 0.2rem;
  cursor: pointer;
}

.flex {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}
.outer-flex {
  display: flex;
  gap: 4rem;
  align-items: center;
  justify-content: space-between;
}

.my-items {
  position: absolute;
  top: 8rem;
}

.fa-check {
  border: 1px solid black;
  border-radius: 100px;
}

button {
  cursor: pointer;
  background: transparent;
  border: 0;
  font-size: 1rem;
}

.strike {
  text-decoration: line-through;
  color: gray;
}

.check-gray {
  border: 1px solid gray;
  color: gray;
}

.close-gray {
  color: gray;
}

.no-strike {
  text-decoration: none;
  color: black;
}
/*
* https://frontendeval.com/questions/shopping-list
*
* Create a shopping list app with autocomplete item entry
*/

const search = document.querySelector('#search');
const results = document.querySelector('.results');
const itemsUI = document.querySelector('.my-items');

let myItems = [];

function debounce(callbackFn, time) {
  let timeoutId;

  return function (...args) {
    if (timeoutId) clearInterval(timeoutId);
    timeoutId = setTimeout(() => {
      callbackFn(args);
    }, time);
  };
}

const fetchItemsOnType = debounce(fetchItems, 500);

async function fetchItems(item) {
  const res = await fetch(`https://api.frontendeval.com/fake/food/${item}`);
  const data = await res.json();
  showSearchResults(data);
}

function showSearchResults(data) {
  data?.length >= 1
    ? results.classList.add('show-results')
    : results.classList.remove('show-results');
  const output = data?.map((item) => {
    return `<p onclick="handleItems(this)">${item}</p>`;
  });
  results.innerHTML = output.join('');
}

function handleItems(e) {
  myItems.push({ item: e.textContent, id: Math.random() });
  results.classList.remove('show-results');
  search.value = '';
  showItems(myItems);
}

function showItems(items) {
  if (items.length === 0) {
    itemsUI.innerHTML = '<p>No items in the list 📪 </p>';
  } else {
    const output = items?.map((item, i) => {
      return `
        <div class="outer-flex">
            <div class="flex">
                <button id=${item.id} onclick="toggleCheck(this)">
                    <i class="${
                      item?.isDone ? 'check-gray fa fa-check ' : 'fa fa-check '
                    }" aria-hidden="true"></i>
                </button>
                <p class="${item?.isDone ? 'strike' : 'no-strike'}">${
        item.item
      }</p>
            </div>
            <button onclick="removeItem(${i})">
                <i class="${
                  item?.isDone ? 'close-gray fa fa-close' : 'fa fa-close'
                }" aria-hidden="true"></i>
            </button> 
        </div>
    `;
    });
    itemsUI.innerHTML = output.join('');
  }
}

function removeItem(id) {
  myItems?.splice(id, 1);
  showItems(myItems);
}

function toggleCheck(e) {
  const newItem = myItems?.map((item) => {
    if (item.id === Number(e.id)) {
      item.isDone ? (item.isDone = false) : (item.isDone = true);
    }
    return item;
  });

  console.log(newItem);

  showItems(newItem);
}

search.addEventListener('input', () => {
  fetchItemsOnType(search.value);
});
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.