Build a Cash Register Project - Build a Cash Register

Tell us what’s happening:

Hi! I believe all the tests pass when I run my cash register on replit, but they don’t seem to pass on the freeCodeCamp IDE. I think it might be because I built my cash register 2D array with the largest denominations first. Ex, cid[0] === [“ONE HUNDRED, 100], etc. Can someone take a look at my code and see if there’s some other error in there?

Edited to add: Tests 7, 9, and 10 fail.
7.) Where price is 3.26 and cash is 100 (can’t give more 20s than exist in the drawer)
9.) Where price is 19.5 and cash is 20 (can’t give change that isn’t there)
10.) Where price is 19.5 and cash is 20 (change that makes the register run out of change exactly returns CLOSED to the display)

Thanks so much!

Your code so far

HTML:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Cash Register</title>
  <link href="style.css" rel="stylesheet" type="text/css" />
</head>

<body>
  <h1>Cash Register Project</h1>
  <div id="change-due"></div>
  <div id="form-wrapper">
    <p id="input-label">Enter cash from customer:</p>
    <input id="cash" />
    <button type="submit" id="purchase-btn">Purchase</button>
  </div>
  <div id="cash-register-top">
    <p id="price-screen"></p>
  </div>
  <div id="change-in-drawer">
  </div>
  
  
  <script src="script.js"></script>
  <script src="https://replit.com/public/js/replit-badge-v2.js" theme="dark" position="bottom-right"></script>
</body>

</html>

CSS:

html {
  height: 100%;
  width: 100%;
}

body {
  background-color: darkblue;
  color: lightgrey;
  display: block;
}

h1 {
  font-size: 2.5rem;
  margin: 20px auto;
  text-align: center;
}

div {
  display: block;
}

#change-due {
  margin: auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

#form-wrapper {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  margin: 10px 0 20px;
}

input {
  margin-bottom: 10px;
}

button {
  cursor: pointer;
  width: 100px;
  height: 30px;
  margin: 10px;
  color: #0a0a23;
  font-size: 18px;
  font-weight: bold;
  background-color: #feac32;
  background-image: linear-gradient(#fecc4c, #ffac33);
  border-color: #feac32;
  border-width: 3px;
  border-radius: 3px;
}

#cash-register-top {
  border: 10px solid #99c9ff;
  background-color: black;
  height: 50px;
  width: 200px;
  color: white;
  font-size: 1.2rem;
  text-align: center;
  align-items: center;
  margin: auto;
}

#change-in-drawer {
  margin: 10px auto;
  padding-top: 10px;
  border: 10px solid#99c9ff;
  background-color: black;
  color: white;
  height: 250px;
  width: 200px;
  font-size: 1.2 rem;
  text-align: center;
  align-items: center;
}

#change-in-drawer p {
  margin: 2px auto;
}

And now the JS:

const cash = document.getElementById("cash");
const purchaseBtn = document.getElementById("purchase-btn");
const changeDueDiv = document.getElementById("change-due");
const changeInDrawer = document.getElementById("change-in-drawer")
const priceScreen = document.getElementById("price-screen");

const statusOptions = ["INSUFFICIENT_FUNDS", "CLOSED", "OPEN"];

let price = 3.26;
const displayPrice = (pr) => {
  priceScreen.innerHTML = `<p>$${price.toFixed(2)}</p>`
}

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

const cidValues = [100, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01]

const getTotalCash = (cashInDrawer) => {
  return cashInDrawer.reduce((acc, currVal) => acc + currVal[1], 0);
}

const displayDrawer = () => {
  changeInDrawer.innerHTML = `
  <p>Change in drawer:</p>
  <p>Pennies: $${cid[8][1].toFixed(2)}</p>
  <p>Nickels: $${cid[7][1].toFixed(2)}</p>
  <p>Dimes: $${cid[6][1].toFixed(2)}</p>
  <p>Quarters: $${cid[5][1].toFixed(2)}</p>
  <p>Ones: $${cid[4][1].toFixed(2)}</p>
  <p>Fives: $${cid[3][1].toFixed(2)}</p>
  <p>Tens: $${cid[2][1].toFixed(2)}</p>
  <p>Twenties: $${cid[1][1].toFixed(2)}</p>
  <p>Hundreds: $${cid[0][1].toFixed(2)}</p>
  `
}

displayDrawer();
displayPrice(price);

purchaseBtn.addEventListener("click", () => {
  const changeDue = (cash.value - price).toFixed(2);
  changeDueDiv.innerHTML = ``
  whichBills(changeDue);
  displayDrawer()
  cash.value = ""
})

const whichBills = (change) => {
  if (change == 0) {
    changeDueDiv.innerHTML =  `<p>No change due - customer paid with exact cash</p>`
  } else if (change < 0) {
    alert("Customer does not have enough money to purchase the item")
  } else if (change > getTotalCash(cid)) {
    changeDueDiv.innerHTML = `<p>Status: ${statusOptions[0]}</p>`;
    // also if cannot return exact change
  } else if (change == getTotalCash(cid)) {
    changeDueDiv.innerHTML = `<p>Status: ${statusOptions[1]}</p>`;
  } else {
    changeDueDiv.innerHTML = `<p>Status: ${statusOptions[2]}</p>`;
    giveBills(change)
  }
}

const giveBills = (change) => {
  const changeArr = [
    ["ONE HUNDRED", 0],
    ["TWENTY", 0],
    ["TEN", 0],
    ["FIVE", 0],
    ["ONE", 0],
    ["QUARTER", 0],
    ["DIME", 0],
    ["NICKEL", 0],
    ["PENNY", 0]
  ];
  
  cid.forEach((denomination, index) => {
    while (change >= cidValues[index] && cid[index][1] != 0) {
      change = Number.parseFloat(change).toFixed(2);    
      changeArr[index][1]++;
      cid[index][1] -= (1 * cidValues[index]);
      cid[index][1].toFixed(2);
      change -= cidValues[index];
    }
  });

  console.log("change after loops: " + change)
  if (change > 0) {
    changeDueDiv.innerHTML = `${statusOptions[0]}`;
    return;
  }
  
  changeArr.forEach((denomination, index) => { 
    if (denomination[1] > 0) {
      changeDueDiv.innerHTML += `
        <p>${denomination[0]}: $${denomination[1] * cidValues[index]}</p>
      `
    }
  });
  return;
}
 

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2.1 Safari/605.1.15

Challenge Information:

Build a Cash Register Project - Build a Cash Register

I think you are right regarding the reason why these tests fail. If the initial cid is replaced with the one from test case it will give different result than what is expected.

Thanks for writing. I reversed my cid, so it starts with the smallest denominations. Then I copied and reversed that new cid in the #giveBills function so my logic could stay the same.

I got all the tests to pass except the last one. My change-due element contains exactly as described in the test, unless I’m missing something?

It says "the value in the #change-due element should be Status: CLOSED QUARTER: $0 DIME: $0 NICKEL: $0 PENNY: $0.5 .”

Here is my new JS file. Can someone check this out and let me know why it isn’t passing?

Oh, I’m also aware that #giveBills is starting to sprawl…I figured I’d ask for help before refactoring. Thanks so much!

const cash = document.getElementById("cash");
const purchaseBtn = document.getElementById("purchase-btn");
const changeDueDiv = document.getElementById("change-due");
const changeInDrawer = document.getElementById("change-in-drawer")
const priceScreen = document.getElementById("price-screen");

const statusOptions = ["INSUFFICIENT_FUNDS", "CLOSED", "OPEN"];

let price = 19.5;
const displayPrice = (pr) => {
  priceScreen.innerHTML = `<p>$${price.toFixed(2)}</p>`
}

let cid = [
  ["PENNY", 0.5],
  ["NICKEL", 0],
  ["DIME", 0],
  ["QUARTER", 0],
  ["ONE", 0],
  ["FIVE", 0],
  ["TEN", 0],
  ["TWENTY", 0],
  ["ONE HUNDRED", 0],
]

const cidValues = [100, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01]

const getTotalCash = (cashInDrawer) => {
  return cashInDrawer.reduce((acc, currVal) => acc + currVal[1], 0);
}

const displayDrawer = () => {
  changeInDrawer.innerHTML = `
  <p>Change in drawer:</p>
  <p>Pennies: $${Math.abs(cid[0][1]).toFixed(2)}</p>
  <p>Nickels: $${Math.abs(cid[1][1]).toFixed(2)}</p>
  <p>Dimes: $${Math.abs(cid[2][1]).toFixed(2)}</p>
  <p>Quarters: $${Math.abs(cid[3][1]).toFixed(2)}</p>
  <p>Ones: $${Math.abs(cid[4][1]).toFixed(2)}</p>
  <p>Fives: $${Math.abs(cid[5][1]).toFixed(2)}</p>
  <p>Tens: $${Math.abs(cid[6][1]).toFixed(2)}</p>
  <p>Twenties: $${Math.abs(cid[7][1]).toFixed(2)}</p>
  <p>Hundreds: $${Math.abs(cid[8][1]).toFixed(2)}</p>
  `
}

displayDrawer();
displayPrice(price);

purchaseBtn.addEventListener("click", () => {
  const changeDue = (cash.value - price).toFixed(2);
  changeDueDiv.innerHTML = ``
  whichBills(changeDue);
  displayDrawer()
  cash.value = ""
})

const whichBills = (change) => {
  if (change == 0) {
    changeDueDiv.innerHTML =  `<p>No change due - customer paid with exact cash</p>`
  } else if (change < 0) {
    alert("Customer does not have enough money to purchase the item")
  } else if (change > getTotalCash(cid)) {
    changeDueDiv.innerHTML = `<p>Status: ${statusOptions[0]}</p>`;
  // } else if (change == getTotalCash(cid)) {
  //   console.log("change is equal to cid")
  //   changeDueDiv.innerHTML = `<p>Status: ${statusOptions[1]}</p>`;
  } else {
    giveBills(change)
  }
}

const giveBills = (change) => {
  changeDueDiv.innerHTML = "";
  const changeArr = [
    ["ONE HUNDRED", 0],
    ["TWENTY", 0],
    ["TEN", 0],
    ["FIVE", 0],
    ["ONE", 0],
    ["QUARTER", 0],
    ["DIME", 0],
    ["NICKEL", 0],
    ["PENNY", 0]
  ];

  const cidStr = JSON.stringify(cid);
  const cidCopy = JSON.parse(cidStr);
  let reversedCid = cidCopy.reverse();
  reversedCid.forEach((denomination, index) => {
    // if value of denomination is less than change due, AND there is nothing in the drawer, changeDueDiv.innerHTML += changeArr[index][1]
    // then the status will have to be prepended
    // and actual change due will be appended
    if (cidValues[index] <= change && reversedCid[index][1] === 0) {
      changeDueDiv.innerHTML += `
        <p>${denomination[0]}: $${denomination[1] * cidValues[index]}</p>
      `
    }
    while (change >= cidValues[index] && reversedCid[index][1] != 0) {
      change = Number.parseFloat(change).toFixed(2); 
      changeArr[index][1]++;
      reversedCid[index][1] -= (1 * cidValues[index]);
      reversedCid[index][1].toFixed(2);
      change -= cidValues[index];
    }
  });
  if (change > 0) {
    changeDueDiv.innerHTML = `Status: ${statusOptions[0]}`;
    return;
  }

  cid = reversedCid.slice().reverse();
  
  console.log(Math.round(getTotalCash(cid)))
  if (Math.round(getTotalCash(cid)) == 0) {
    console.log("in getTotalCash");
    const statusNode = document.createElement("p");
    statusNode.innerHTML = `Status: ${statusOptions[1]}`
    changeDueDiv.prepend(statusNode);
    changeArr.forEach((denomination, index) => { 
      if (denomination[1] > 0) {
        changeDueDiv.innerHTML += `
          <p>${denomination[0]}: $${denomination[1] * cidValues[index]}</p>
        `
      }
    });
    return;
  }
  changeDueDiv.innerHTML += `<p>Status: ${statusOptions[2]}</p>`;
  changeArr.forEach((denomination, index) => { 
    if (denomination[1] > 0) {
      changeDueDiv.innerHTML += `
        <p>${denomination[0]}: $${denomination[1] * cidValues[index]}</p>
      `
    }
  });
  return;
}

Last test has bug (internally it expected OPEN status instead of CLOSED). Fix is already done in the codebase, once next deployment happens it will be also reflected on the page.

I love to see this. I was worried that something was deep down in the structure of my thinking that would have to change. :rofl:

I’m assuming that bug fix hasn’t gone through yet? I’ve been staring at this test for like 30 minutes. Lol.

Unfortunately not yet!