Build a Cash Register Project - Build a Cash Register

Tell us what’s happening:

Your code so far

WARNING

The challenge seed code and/or your solution exceeded the maximum length we can port over from the challenge.

You will need to take an additional step here so the code you wrote presents in an easy to read format.

Please copy/paste all the editor code showing in the challenge from where you just linked.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="./styles.css" type="text/css" rel="stylesheet">
    <title>Cash Register</title>
  </head>
  <body>
    <div id="page-container">
      <div id="register-background">
        <div id="register-screen"></div>
        <div id="register-side"></div>
        <div id="register-front">
          <div class="decor-btn"></div>
          <div class="decor-btn"></div>
          <div class="decor-btn"></div>
        </div>
      </div>
      <div id="enter-hide-change">
        <button type="button" id="enter-hide-btn">
          Open Register Buttons
        </button>
        <button type="button" id="purchase-btn">
          Purchase
        </button>
      </div>
      <label for="cash">Input Change Here:
        <input id="cash" type="text">
      </label>
      <div id="change-in-drawer"></div>
      <div id="change-due"></div>
      <div id="buttons-array">
        <div class="register-btns">1</div>
        <div class="register-btns">2</div>
        <div class="register-btns">3</div>
        <div class="register-btns">4</div>
        <div class="register-btns">5</div>
        <div class="register-btns">6</div>
        <div class="register-btns">7</div>
        <div class="register-btns">8</div>
        <div class="register-btns">9</div>
        <div class="register-btns" id="point">.</div>
        <div class="register-btns" id="dollar">$</div>
        <div class="register-btns" id="clear">CLR</div>
        <div class="register-btns" id="enter">Enter</div>
      </div>
    </div>
  </body>
  <script src="./script.js"></script>
</html>
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]
];

/* Used to determine how many "bills" from each currency category are needed from the cash register to make change (If the cash register has enough change). */
const ca = [0.01, 0.05, 0.10, 0.25, 1, 5, 10, 20, 100];

/*Text input element where the user inputs their cash amount.*/
const cash = document.getElementById("cash");

/*Decorative buttons on the cash register, created in Javascript since they're many of the same design whose creation can be simplified through iterables.*/
const displayBtns = document.querySelectorAll(".decor-btn");

/*Optional GUI which achieves the same purpose as the text input, for flavor.*/
const registerBtns = document.querySelectorAll(".register-btns");

/*Displays the amount of change entered on the cash register graphic.*/
const registerScreen = document.getElementById("register-screen");

/*Graphical GUI parent/container element, selected so visibility can be toggled later.*/
const btnParent = document.getElementById("buttons-array");

/*Button which toggles GUI visibility when clicked.*/
const registerToggle = document.getElementById("enter-hide-btn");

/*Where final output of cash register app will go.*/
const output = document.getElementById("change-due");

/*Clear button on optional GUI, gets rid of all user input and subsequent graphics/text.*/
const clear = document.getElementById("clear");

/*Purchase button that initiates the change exchange calculations and subsequent display in the DOM*/
const purchaseBtn = document.getElementById("purchase-btn");

/*Container that will display the currency left in the drawer after purchasing*/
const cidDisplay = document.getElementById("change-in-drawer");

/*Counter variable that will change the functionality of the GUI buttons based on its value, is incremented in an iterator later.*/
let counter = 1;

/*Variables that handle optional floating point values in the GUI; makes it possible to input both integers and floating point values.*/
let pointToggle = false;
let pointString = "";

/*Boolean array that prevents entering information into both the text box and GUI (Only one can be true at any given moment, when either the input or a GUI button is activated).*/
let toggle = [false, false];

/*Create the display buttons on the cash register, assign styles.*/
for(let i=0; i<3; i++) {
  displayBtns[i].style.left = `min(${10*i + 5}vw, ${70 + i*120}px)`;
  displayBtns[i].style.top = `calc((min(4vw, 40px) / -2) * (${2*i + 1}))`;
}

/*Adds functionality to the GUI Buttons.*/
registerBtns.forEach((el) => {
  /*Assigns grid areas to each GUI button, styling it.*/
  el.style.gridArea = `button${counter}`;

  /*If the button is a button whose value is meant to be added to the cash register screen, add its functionality to do so.*/
  if(counter < 12) {
    el.addEventListener("click", () => {
      /*Turn on the GUI toggle boolean, removing all data from the text input in the process.*/
      toggle[1] = true;
      if(toggle.every(el => el)) {
        toggle[0] = false;
        registerScreen.textContent = "";
      }
      /*If the point button is pressed, turn on pointToggle so that a floating point can be entered and then compared against the inputValidation function. Point and two following numbers (Or an incorrect input message) will not be shown until 3 characters are entered.*/
      if(el.textContent == "." && !registerScreen.textContent.includes(".") && !pointString.includes(".")) {
        pointToggle = true;
      }
        /*If pointToggle is activated, keep adding subsequent characters entered on the GUI until there's 3 of them. Then, send them to the inputValidation function alongside the previous characters entered (Displayed within the register screen).*/
        pointToggle ? pointString += el.textContent : inputValidation(registerScreen.textContent + el.textContent);
      if(pointString.length == 3) {
         inputValidation(registerScreen.textContent + pointString);
         pointToggle = false;
         pointString = ""; 
      }
    })
    /*Add functionality to the clear button, which removes the input text from everything on the page.*/
  } else if (counter == 12) {
    el.addEventListener("click", () => {
      output.textContent = "";
      registerScreen.textContent = "";
      cash.value = "";
    })
  }
  /*Increment the counter to move onto the next GUI button in the subsequent loop.*/
  counter++;
})
/*Set the GUI element to be hidden on page load.*/
btnParent.style.display = "none";
/*Add toggle functionality to the register buttons button, which opens/closes the GUI when clicked.*/
registerToggle.addEventListener("click", () => {
  if(btnParent.style.display == "none") {  
    btnParent.style.display = "grid";
    registerToggle.textContent = "Hide Register Buttons";
  }  
  else {
    btnParent.style.display = "none";
    registerToggle.textContent = "Open Register Buttons";
  }
})
/*Adds an event listener which removes any input by the GUI (If applicable), and validates the textbox value on every key press.*/
cash.addEventListener("keyup", () => {
  toggle[0] = true;
  if(toggle.every(el => el)) {
    toggle[1] = false;
    registerScreen.textContent = "";
  }
  inputValidation(cash.value);
})

/*Functionality for the purchase button, begins calculation/display process.*/
purchaseBtn.addEventListener("click", () => {
  /*Clears the output in case there is any prior error messages or purchase messages*/
  output.innerHTML = "";
  /*cleanedDisplay removes the optional and allowed dollar sign so it can be used in calculation. Both the textbox and GUI input a value into the register screen, so this works for both.*/
  let cleanedDisplay = parseFloat(registerScreen.textContent.replace("$", ""));
  /*Textbox input cleanup for direct comparison to pass some of the tests.*/
  cash.value = cash.value.replace("$", "");

  /*Variable that holds the amount of change needed from the register. cleanedDisplay is chosen since both input methods make the register screen display a value.*/
  let changeDue = cleanedDisplay - price;
  /*Variable that will hold the amount of cash left in the register, to determine whether change can be made or not (Or if it's necessary).*/
  let registerCash = 0;
  /*Goes through each bill type, adding up the values into the registerCash variable.*/
  cid.forEach(el => registerCash += el[1]);

  /*If the entered money is less than the price, indicate that the customer does not have enough money. Break out of the function.*/
  if(cleanedDisplay < price || parseFloat(cash.value) < price) {
    alert("Customer does not have enough money to purchase the item");
    return;
  }
  /*If the entered money is exactly equal to the price, indicate that no change needs to be made. Break out of the function.*/
  if(cleanedDisplay == price || parseFloat(cash.value) == price) {
    output.innerHTML = "<p>No change due - customer paid with exact cash</p>";
    return;
  }
  /*If the cash the change due is more than the cash available in the register, indicate in the output that there are insufficient funds.*/
  if(registerCash < changeDue) {
    output.innerHTML += "<p>Status: INSUFFICIENT_FUNDS</p>";
  }
  else {
    /*If the cash register has the exact amount of change due, indicate the register is closed. Otherwise, state that it's open.*/
    registerCash == changeDue ? output.innerHTML += "Status: CLOSED" : output.innerHTML += "Status: OPEN";
    /*Start at the end of the CID array and perform the necessary calculations while working backward, so that the largest-to-smallest requirement can be fulfilled.*/
    for(let iterator = cid.length - 1; iterator >= 0; iterator--) {
      /*Accumulator variable to show how much of each bill type is required to make change.*/
      let accumulator = 0;
      /*If the change due is less than or equal to the total amount of the current bill type (i.e hundreds, twenties, etc), set the change needed to be removed from the register to the amount of bills required to get the change due "below" the value of the bill. If the change due is more than the total of the current bill type, simply give all the available value in that bill type.  For example, if the change due is $300 and there is $800 in hundreds in the register, then changeForRound would be $300 for hundreds. If the change due was $800 and there was $400 in hundreds in the register, changeForRound would be $400.*/
      let changeForRound = changeDue <= cid[iterator][1] ? Math.floor(changeDue / ca[iterator]) * ca[iterator] : cid[iterator][1];

      /*Conditional that subtracts the value from the due change only if necessary for the bill type. Were changeForRound larger than changeDue, then it would move onto a smaller bill type to see if change can be made.*/
      if(changeForRound <= changeDue) {
        /*Rounding error fix for last calculation for ChangeForRound.*/
        iterator == 0 ? changeForRound = Math.round(changeDue / ca[iterator]) * ca[iterator] : null;
        /*Subtract/add from/to the relevant values based on the change for this iteration of the loop.*/
        cid[iterator][1] -= changeForRound;
        changeDue -= changeForRound;
        accumulator += changeForRound;
      }
      /*If there was any money taken from the drawer (stored in the accumulator variable), display it in the output alongside the bill type*/
      if(accumulator > 0) {
        output.innerHTML += ` ${cid[iterator][0]}: $${Math.round(accumulator * 100) / 100}`;
      }
    }
    /*Shows the amount left in the register after each transaction*/
    cidDisplay.innerHTML = "<h1>Current change in drawer:</h1>"
    cid.forEach((el) => {
      let newElement = document.createElement("div");
      newElement.innerHTML = `<p>${el[0]}, $${el[1]}</p>`;
      cidDisplay.appendChild(newElement);
    })
  }
})

/*Input validation that allows optional dollar sign or floating point. Floating point is only allowed if it is followed by two digits (to represent cents)*/
function inputValidation(input) {
  if(input.match(/^[\$?\d+]\d*?(\.\d{2})?$/)) {
    registerScreen.textContent = input;
    output.textContent = "";
  } 
  else {
    output.textContent = "Please Enter a valid number";
  }
}

Hello, currently trying to finish this project but am unable to fulfill the bottom 5 tests (Where the cash, price, and cid array are compared) and I’m not exactly sure why. Do we need to directly integrate the cash value into our calculations? Am I using the wrong array/variable/element to print the results? I’m getting the correct change amounts on the page, not sure what’s happening. I’ve been stuck on this project for three days, and I’m sure it’s something relatively simple. Any assistance here would be greatly appreciated.

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0

Challenge Information:

Build a Cash Register Project - Build a Cash Register

Hello, is there some reason so many lines of code have been commented out?
This might help:

They’re supposed to be comments so people can follow what the code is doing; I put them there because the code is kind of long

It appears that when tests are run, the status is Status: OPEN almost in every case. I’m not entirely sure why that happens, there might be some additional, external variable that calculating function is depending on, but I’m unable to pin-point the exact cause.

Keep in mind that tests are run one-by-one, after changing cid, price and #cash element, without reloading whole page. On the other hand when code is changed manually, the preview is loaded again, which results in executing the whole code. If there’s some additional dependency, that’s updated only when the page is loaded, it can cause tests to fail.

At some point this can have the opposite result. Generally comments should only explain why something is done in code. The what happens should be clear from the code itself - code will need to be read anyway.