Build a Cash Register Project

I’m failing the #13, #17, #18, #19 tests. Sometimes I guess I pass the #13 test. For the #18 when I test on my browser or FCC’s platform with the values given in #18 steps it gives the required result but is not passing the test idk why. Help!

Link to tests: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures-v8/build-a-cash-register-project/build-a-cash-register

HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link
      rel="icon"
      type="image/png"
      href="https://cdn.freecodecamp.org/universal/favicons/favicon.ico"
    />

    <title>Cash Register Project - Srishti</title>

    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <main>
      <img
        class="freecodecamp-logo"
        src="https://cdn.freecodecamp.org/platform/universal/fcc_primary.svg"
        alt="freeCodeCamp Logo"
      />

      <h1>Cash Register Project</h1>

      <form id="form">
        <div id="change-due">
        </div>
        <label for="cash">Enter cash from customer:</label>
        <input type="number" id="cash" />
        <button id="purchase-btn" type="submit">Purchase</button>
      </form>

      <div id="cash-register">
        <div class="display">
          <p id="total">Total: $3.26</p>
        </div>
        <div class="register-body">
          <div class="keypad">
            <div class="key"></div>
            <div class="key"></div>
            <div class="key"></div>
            <div class="key"></div>
            <div class="key"></div>
            <div class="key"></div>
            <div class="key"></div>
            <div class="key"></div>
            <div class="key"></div>
          </div>
          <div class="change-in-drawer">
            <p class="bold">Change in drawer:</p>
            <p>Pennies: $<span>1.01</span></p>
            <p>Nickels: $<span>2.05</span></p>
            <p>Dimes: $<span>3.1</span></p>
            <p>Quarters: $<span>4.25</span></p>
            <p>Ones: $<span>90</span></p>
            <p>Fives: $<span>55</span></p>
            <p>Tens: $<span>20</span></p>
            <p>Twenties: $<span>60</span></p>
            <p>Hundreds: $<span>100</span></p>
          </div>
        </div>
        <div class="lower-box">
          <div class="lock"></div>
        </div>
      </div>
    </main>
    <script src="script.js"></script>
  </body>
</html>

CSS:

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

:root {
  --bg-color: #0a0a23;
  --font-color: white;
  --register-color: #99c9ff;
  --font-color-alt: black;
}

body {
  background-color: var(--bg-color);
  color: var(--font-color);
  font-family: Verdana, Geneva, Tahoma, sans-serif;
  padding: 2rem;
}

main,
form,
.lower-box {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

main img {
  width: 80%;
  max-width: 16rem;
}

h1 {
  margin: 2.8rem 0 2.2rem;
  text-align: center;
}

.bold {
  font-weight: 700;
}

/* form */
form {
  gap: 0.5rem;
}

input {
  width: 90%;
  max-width: 13rem;
  display: block;
  padding: 5px 10px;
  font-size: 1rem;
}

button {
  background: linear-gradient(#fec94a, #ffaf36);
  border: 1px inset #ffaf36;
  font-size: 1.1rem;
  font-weight: 700;
  padding: 5px;
  margin-top: 1rem;
  cursor: pointer;
}

/* cash register */
#cash-register .display {
  border: 0.6rem solid var(--register-color);
  width: 100%;
  max-width: 11.4rem;
  height: 3.1rem;
  text-align: center;
  padding: 0.3rem 0;
  margin: 3rem 0 1.7rem 1rem;
}

#cash-register .display::after {
  content: "";
  display: block;
  width: 2.5rem;
  height: 1.8rem;
  background-color: var(--register-color);
  position: relative;
  left: 1rem;
  top: 0.9rem;
}

.register-body {
  background-color: var(--register-color);
  width: 100%;
  max-width: 20.3rem;
  min-height: 15.5rem;
  border-radius: 2rem 2rem 0 0;
  display: flex;
  justify-content: space-between;
  padding: 1.2rem 1.3rem;
  gap: 1rem;
  flex-wrap: wrap;
}

.change-in-drawer {
  background-color: var(--font-color);
  color: var(--font-color-alt);
  height: max-content;
  padding: 0.5rem;
}

.keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.2rem;
  height: max-content;
}

.key {
  width: 0.875rem;
  height: 0.875rem;
  background-color: var(--font-color-alt);
  border-radius: 0.2rem;
}

.lower-box {
  width: 100%;
  max-width: 20.3rem;
  height: 3.1rem;
  background-color: var(--register-color);
  margin-top: 0.7rem;
}

.lower-box .lock {
  width: 1rem;
  height: 1rem;
  background-color: var(--font-color-alt);
  border-radius: 50%;
}

#change-due {
  font-family: "Courier New", Courier, monospace;
  font-size: 2rem;
  margin: 1rem 0 2.5rem;
  text-align: center;
  display: none;
}

/* media queries */
@media only screen and (min-width: 120rem) {
  html {
    font-size: 1.8rem;
  }
}
@media only screen and (min-width: 64rem) {
  .key {
    width: 1.25rem;
    height: 1.25rem;
  }
  #cash-register .display {
    margin-left: 3rem;
  }
  .register-body {
    gap: 2rem;
  }
}

@media only screen and (max-width: 16rem) {
  html {
    font-size: 0.7rem;
  }
  #cash-register .display {
    margin-left: 0;
  }
}

@media only screen and (max-width: 7rem) {
  html {
    font-size: 0.3rem;
  }
}

JS:

const inputEl = document.getElementById("cash");
const purchaseBtn = document.getElementById("purchase-btn");
const output = document.getElementById("change-due");
const changeLeft = document.querySelectorAll(".change-in-drawer span");

let price = 3.26;
let cid = [
  ["PENNY", 1.01],
  ["NICKEL", 2.05],
  ["DIME", 3.1],
  ["QUARTER", 4.25],
  ["ONE", 90],
  ["FIVE", 55],
  ["TEN", 20],
  ["TWENTY", 60],
  ["ONE HUNDRED", 100],
];

let conversionArr = {
  "ONE HUNDRED": 100,
  TWENTY: 20,
  TEN: 10,
  FIVE: 5,
  ONE: 1,
  QUARTER: 0.25,
  DIME: 0.1,
  NICKEL: 0.05,
  PENNY: 0.01,
};

let sortedCid = cid.reverse();

const viewResult = () => {
  output.style.display = "block";
};

const calcChange = (change) => {
  let result = [];
  sortedCid.forEach((arr) => {
    let currVal = conversionArr[arr[0]];
    if (change >= currVal) {
      if (change > arr[1]) {
        if (arr[1] !== 0) {
          change = change.toFixed(2) - arr[1];
          result.push([arr[0] + ": $" + arr[1]]);
          arr[1] = 0;
        }
      } else {
        let n = 0;
        while (change - currVal >= 0) {
          change = change.toFixed(2) - currVal;
          n++;
        }
        result.push([arr[0] + ": $" + n * currVal]);
        arr[1] -= n * currVal;
      }
    }
  });
  return result;
};

const updateChange = (cid) => {
  let i = cid.length;
  Array.from(changeLeft).forEach((n) => {
    n.innerHTML = cid[i - 1][1].toFixed(2);
    i--;
  });
};

const displayChange = (result) => {
  result.forEach((res) => {
    output.innerHTML += `${res}<br>`;
  });
};

const clearResult = () => {
  output.innerHTML = "";
};

const displayStatus = (status) => {
  switch (status) {
    case "open-q":
      status = "OPEN<br>QUARTER: $0.5";
      break;
    case "open":
      status = "OPEN<br>";
      break;
    case "closed":
      status = "CLOSED<br>";
      break;
    case "low-funds":
      status = "INSUFFICIENT_FUNDS";
      break;
    default:
      status = "";
  }
  output.innerHTML = `Status: ${status}`;
};

const correctDenominationsPresent = (conversionArr, cid, change) => {
  let total = 0;

  console.log(change);
  Object.values(conversionArr).forEach((amount) => {
    if (amount < change) {
      console.log("amount:", amount);
      cid.forEach((arr) => {
        if (
          arr[0] ===
          Object.keys(conversionArr).find(
            (key) => conversionArr[key] === amount
          )
        ) {
          total += arr[1];
          console.log("total:", total);
          // console.log(arr[1])
        }
      });
    }
  });
  return total > change;
};

purchaseBtn?.addEventListener("click", (e) => {
  e.preventDefault();
  clearResult();
  viewResult();

  const cash = Number(inputEl.value);
  let change = cash - price;

  let cidTotal = 0;
  sortedCid.forEach((arr) => (cidTotal += arr[1]));
  console.log("cidTotal:", cidTotal);

  if (cash < price || inputEl.value === "") {
    alert("Customer does not have enough money to purchase the item");
  } else if (cash === price) {
    output.innerHTML = "No change due - customer paid with exact cash";
  } else if (
    change === 0.5 &&
    correctDenominationsPresent(conversionArr, cid, change)
  ) {
    displayStatus("open-q");
  } else if (price < cash) {
    if (
      change < cidTotal &&
      correctDenominationsPresent(conversionArr, cid, change)
    ) {
      displayStatus("open");
      displayChange(calcChange(change));
      updateChange(sortedCid);
    } else if (
      change > cidTotal ||
      (correctDenominationsPresent(conversionArr, cid, change) === false &&
        change < cidTotal)
    ) {
      displayStatus("low-funds");
    } else if (change === cidTotal) {
      displayStatus("closed");
      displayChange(calcChange(change));
      updateChange(sortedCid);
    }
  }

  inputEl.value = "";
});

Hi @srishticho

For test 13, how are you checking the available funds in the drawer?

Happy coding

remove all the things in the global space that are not elements or cid and price

Hi,

This part of the code is checking for the #13 condition:

else if (price < cash) {
    if (
      change < cidTotal &&
      correctDenominationsPresent(conversionArr, cid, change)
    ) {
      displayStatus("open");
      displayChange(calcChange(change));
      updateChange(sortedCid);
    }
}

This checks if funds in drawer are more than the change and if denominations are correct as well for the change to be returned.

How about the last if statement?

const inputEl = document.getElementById("cash");
const purchaseBtn = document.getElementById("purchase-btn");
const output = document.getElementById("change-due");
const changeLeft = document.querySelectorAll(".change-in-drawer span");

let price = 3.26;
let cid = [
  ["PENNY", 1.01],
  ["NICKEL", 2.05],
  ["DIME", 3.1],
  ["QUARTER", 4.25],
  ["ONE", 90],
  ["FIVE", 55],
  ["TEN", 20],
  ["TWENTY", 60],
  ["ONE HUNDRED", 100],
];

const viewResult = () => {
  output.style.display = "block";
};

const calcChange = (change, sortedCid, conversionArr) => {
  let result = [];
  sortedCid.forEach((arr) => {
    let currVal = conversionArr[arr[0]];
    if (change >= currVal) {
      if (change > arr[1]) {
        if (arr[1] !== 0) {
          change = change.toFixed(2) - arr[1];
          result.push([arr[0] + ": $" + arr[1]]);
          arr[1] = 0;
        }
      } else {
        let n = 0;
        while (change - currVal >= 0) {
          change = change.toFixed(2) - currVal;
          n++;
        }
        result.push([arr[0] + ": $" + n * currVal]);
        arr[1] -= n * currVal;
      }
    }
  });
  return result;
};

const updateChange = (cid) => {
  let i = cid.length;
  Array.from(changeLeft).forEach((n) => {
    n.innerHTML = cid[i - 1][1].toFixed(2);
    i--;
  });
};

const displayChange = (result) => {
  result.forEach((res) => {
    output.innerHTML += `${res}<br>`;
  });
};

const clearResult = () => {
  output.innerHTML = "";
};

const displayStatus = (status) => {
  switch (status) {
    case "open-q":
      status = "OPEN<br>QUARTER: $0.5";
      break;
    case "open":
      status = "OPEN<br>";
      break;
    case "closed":
      status = "CLOSED<br>";
      break;
    case "low-funds":
      status = "INSUFFICIENT_FUNDS";
      break;
    default:
      status = "";
  }
  output.innerHTML = `Status: ${status}`;
};

const correctDenominationsPresent = (conversionArr, cid, change) => {
  let total = 0;

  console.log(change);
  Object.values(conversionArr).forEach((amount) => {
    if (amount < change) {
      console.log("amount:", amount);
      cid.forEach((arr) => {
        if (
          arr[0] ===
          Object.keys(conversionArr).find(
            (key) => conversionArr[key] === amount
          )
        ) {
          total += arr[1];
          console.log("total:", total);
          // console.log(arr[1])
        }
      });
    }
  });
  return total > change;
};

purchaseBtn?.addEventListener("click", (e) => {
  e.preventDefault();

  let conversionArr = {
    "ONE HUNDRED": 100,
    TWENTY: 20,
    TEN: 10,
    FIVE: 5,
    ONE: 1,
    QUARTER: 0.25,
    DIME: 0.1,
    NICKEL: 0.05,
    PENNY: 0.01,
  };

  let sortedCid = cid.reverse();

  clearResult();
  viewResult();

  const cash = Number(inputEl.value);
  let change = cash - price;

  let cidTotal = 0;
  sortedCid.forEach((arr) => (cidTotal += arr[1]));
  console.log("cidTotal:", cidTotal);

  if (cash < price || inputEl.value === "") {
    alert("Customer does not have enough money to purchase the item");
  } else if (cash === price) {
    output.innerHTML = "No change due - customer paid with exact cash";
  } else if (
    change === 0.5 &&
    correctDenominationsPresent(conversionArr, cid, change)
  ) {
    displayStatus("open-q");
  } else if (price < cash) {
    if (
      change < cidTotal &&
      correctDenominationsPresent(conversionArr, cid, change)
    ) {
      displayStatus("open");
      displayChange(calcChange(change, sortedCid, conversionArr));
      updateChange(sortedCid);
    } else if (
      change > cidTotal ||
      (correctDenominationsPresent(conversionArr, cid, change) === false &&
        change < cidTotal)
    ) {
      displayStatus("low-funds");
    } else if (change === cidTotal) {
      displayStatus("closed");
      displayChange(calcChange(change, sortedCid, conversionArr));
      updateChange(sortedCid);
    }
  }

  inputEl.value = "";
});

I did as you suggested and passed the #18 test but still failing the #13, #17, #19. #13 sometimes passes.

The last if statement checks if the change (eg: 90) is greater than the total amount present for that denomination in the cid.

arr will be something like [“TWENTY”, 60] as it is looping through the sortedCid which is basically just reverse of normal cid. So arr[1] would be 60 and if change is greater than 60 then it would deduct 60 from the change.

So like if (90 > 60) { 90 - 60 = 30 (new change)}

Basically this is to check if we can remove the whole amount for a certain denomination altogether (like all of 100 or 20s or 10s etc) or not. If we can then code inside last if will be executed.

What happens when change and denomination are equal?

else {
        let n = 0;
        while (change - currVal >= 0) {
          change = change.toFixed(2) - currVal;
          n++;
        }

as of now this was being used for it… but now that you have pointed it out I should be checking for it in the if condition only by adding the =

if (change >= arr[1]) {}

Edit: I added the >= operatore there rather than >
Sometimes I’m passing #13 and #19 sometimes i’m not. #17 is not passing.