Tell us what’s happening:
I have passed every test except for the following:
17. When price is less than the value in the #cash element, total cash in drawer cid is greater than change due, but the individual denomination amounts make it impossible to return needed change, when the #purchase-btn element is clicked, the value in the #change-due element should be “Status: INSUFFICIENT_FUNDS”
I’ve tried testing said criteria manually and it worked with a few combinations. The code for this part are in the lines 130-150 (this is a repost);
Your code so far
<!-- file: index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h1>Cash Register Project</h1>
<div id="change-due">
</div>
<label for="cash">Enter cash from customer</label>
<input type="number" placeholder="Payment" id="cash">
<button id="purchase-btn"><b>Purchase</b></button>
<div id="cashRegister">
<div id="display">
<div id="display-screen">
<p id="screen"></p>
</div>
</div>
<div id="neck"></div>
<div id="bigBox">
<div id="pads1">
<div class="pads">
<div></div>
<div></div>
<div></div>
</div>
<div class="pads">
<div></div>
<div></div>
<div></div>
</div>
<div class="pads">
<div></div>
<div></div>
<div></div>
</div>
</div>
<div id="availability">
<p><strong>Available change:</strong></p>
<div id="change"></div>
</div>
</div>
<div id="smallBox">
<div id="circle"></div>
</div>
</div>
</div>
<script src="./script.js"></script>
</body>
</html>
/* file: script.js */
//-----query the stuff first
const input = document.getElementById("cash");
const button = document.getElementById("purchase-btn");
const screen = document.getElementById("screen");
const changeListDiv = document.getElementById("change")
const changeDueDiv = document.getElementById("change-due");
let toDisplay = {
status:"",
'ONE HUNDRED': 0,
'TWENTY': 0,
'TEN': 0,
'FIVE': 0,
'ONE': 0,
'QUARTER': 0,
'DIME': 0,
'NICKEL': 0,
'PENNY': 0
};
//-----initialize variables
let price = 3.75;
let changeMsg = "";
//remaining change
let cid = [
['PENNY', 1.01],
['NICKEL', 0],
['DIME', 10],
['QUARTER', 0],
['ONE', 0],
['FIVE', 0],
['TEN',0],
['TWENTY', 20],
['ONE HUNDRED', 100]
];
//determine currency unit's value
const values = {
'ONE HUNDRED': 100,
'TWENTY': 20,
'TEN': 10,
'FIVE': 5,
'ONE': 1,
'QUARTER': 0.25,
'DIME': 0.1,
'NICKEL': 0.05,
'PENNY': 0.01
}
//-----display available information
screen.innerText = `$${price}`
const updateAvailableChange = () => {
changeListDiv.innerHTML = "";
cid.forEach((item) => {
const pTag = document.createElement("p");
pTag.classList.add("change");
pTag.appendChild(
document.createTextNode(`${item[0]}: $${formatNumber(item[1])}`)
);
changeListDiv.appendChild(pTag);
});
};
//renders the change due
const updateChangeDueDiv = () => {
let divMsg = `<p>Status: ${toDisplay.status}</p>`;
Object.keys(toDisplay).slice(1).forEach((key) => {
if (toDisplay[key]) {
divMsg += `<p>${key}: $${formatNumber(toDisplay[key])}</p>`;
}
});
changeDueDiv.innerHTML = divMsg;
};
//renders the available change
updateAvailableChange();
//utility functions
function getKeyByValue(object, value) {
return Object.keys(object).find(key => object[key] === value);
}
function findAvailablecid(name){
return cid.find((item)=>item[0]===name)[1];
}
function findIndexcid(name){
return cid.findIndex((item)=>item[0]===name);
}
function formatNumber(num) {
// Check if the number has decimal places
if (num % 1 !== 0) {
return parseFloat(num.toFixed(2)); // Round to 2 decimal places
}
return num; // Return as an integer
}
//the main function thing
const insufficientFunds = ()=>{
toDisplay.status = "INSUFFICIENT_FUNDS"
updateChangeDueDiv();
}
const noDue = ()=>{
changeDueDiv.innerHTML = "<p>No change due - customer paid with exact cash</p>";
}
//main function for this project
const reduceValue = () => {
toDisplay = {
status:"",
'ONE HUNDRED': 0,
'TWENTY': 0,
'TEN': 0,
'FIVE': 0,
'ONE': 0,
'QUARTER': 0,
'DIME': 0,
'NICKEL': 0,
'PENNY': 0
};
let payment = parseFloat(input.value).toFixed(2);
let toReturn = parseFloat((payment - price).toFixed(2));
let maxVal = Infinity;
let totalChange = 0;
let totalReturnableChange = 0;
//calculate total change available
cid.forEach((item) => totalChange = parseFloat((totalChange + item[1]).toFixed(2)));
//calculate change that we can actually return (which is the denominations below or equal to the amount we have to return)
//this code takes the part of cid that is below or equal to what needs to be returned, and then sums it up (to put it simply)
cid.slice(0,cid.findIndex((item)=>item[0]===Object.keys(values).find((item)=>values[item]===Object.values(values).find((item) => item<=toReturn)))+1).forEach((item)=>totalReturnableChange = parseFloat((totalReturnableChange + item[1]).toFixed(2)));
//checks if the amount of cash given is enough
if (toReturn < 0) {
alert("Customer does not have enough money to purchase the item");
return;
} else if (toReturn === 0) {
noDue();
return;
}
//checks if we have enough change available
if (toReturn > totalChange) {
insufficientFunds();
return;
}
//checks if we have enough returnable change available (ik this one makes the other one pointless but its fine)
if(toReturn>totalReturnableChange){
insufficientFunds();
return;
}
//keeps looking and reducing as long as there is still a remaining toReturn
while (toReturn > 0) {
let reducer = Object.values(values).find((item) => item <= toReturn && item < maxVal);
// If no reducer is found, insufficient funds
if (!reducer) {
insufficientFunds();
break;
}
let reducerName = getKeyByValue(values, reducer);
// Find available funds for the currency
let reducerAvailablecid = findAvailablecid(reducerName);
if (reducerAvailablecid === undefined) {
maxVal = reducer;
continue;
}
console.log(`Availablecid: ${reducerAvailablecid}`);
// If there is not enough of this currency, skip to the next one
if (reducerAvailablecid - reducer < 0) {
maxVal = reducer;
continue;
}
// Deduct from cid and reduce toReturn
const index = findIndexcid(reducerName);
cid[index][1] = parseFloat((cid[index][1] - reducer).toFixed(2));
toReturn = parseFloat((toReturn - reducer).toFixed(2));
//updates the amount of this currency (reducer) to display
toDisplay[reducerName]+=parseFloat(values[reducerName].toFixed(2));
console.log(`Remaining toReturn: ${toReturn}`);
}
totalChange=0;
cid.forEach((item) => totalChange = parseFloat((totalChange + item[1]).toFixed(2)));
//checks if there is still change left
console.log("cid is now " + cid);
console.log("total change now is: " + totalChange);
if(totalChange){
toDisplay.status = "OPEN";
input.value = "";
}else{
toDisplay.status = "CLOSED"
}
updateChangeDueDiv();
updateAvailableChange();
};
button.addEventListener("click", reduceValue);
input.addEventListener('keydown', e => {
if (e.key === 'Enter') {
reduceValue(); }
});
/* file: styles.css */
html, body{
height:100%;
width:100%;
padding: 0;
background-color: rgba(9, 13, 57, 0.93);
color:white;
}
body{
display:flex;
justify-content: space-evenly;
}
.container{
width:60%;
height:100%;
text-align: center;
display: flex;
flex-direction: column;
}
.container >*{
margin: 10px;
}
#cash{
margin-top: 0;
width: 50%;
margin-left:auto;
margin-right: auto;
height: 20px;
}
#purchase-btn{
width: 30%;
margin-left:auto;
margin-right: auto;
height: 30px;
transition: all 0.2s;
}
#purchase-btn:hover{
background-color: orange;
width: 35%;
}
#purchase-btn:active{
background-color: red;
}
#cashRegister{
height: 50%;
width: 90%;
margin-left: auto;
margin-right: auto;
min-width: 450px;
max-width: 450px;
}
#cashRegister>*{
background-color:rgba(99, 43, 117, 0.93);
}
#display {
margin: 0;
margin-left: 100px;
height: 40px;
width: 200px;
margin-top: 10px;
display: flex;
justify-content: center;
align-items: center; /* Centers content inside */
}
#display-screen {
display: flex; /* Enable flexbox */
justify-content: center; /* Center horizontally */
align-items: center; /* Center vertically */
margin: 0; /* Remove auto margins */
height: 70%;
width: 95%;
background-color: black;
}
#screen{
margin:0;
color: white;
}
#neck{
width: 20px;
height: 60px;
margin-left: 140px;
}
#bigBox{
height: 70%;
min-height: 300px;
max-height: 300px;
width: 90%;
border-top-right-radius: 50px 40%;
border-top-left-radius: 50px 40%;
margin-left: 20px;
display: flex;
}
#pads1{
background-color: grey;
height: 100px;
width: 100px;
margin:30px;
margin-right: 0;
display: flex;
}
.pads{
height: 100%;
width: auto;
flex-direction: column;
align-items: center;
justify-content: center;
margin:0;
}
.pads>*{
background-color: whitesmoke;
width: 20px;
height: 20px;
margin: 10px;
margin-right: 0px;
}
#smallBox{
height: 50px;
margin-top: 15px;
width: 90%;
margin-left: 20px;
display: flex;
align-items: center;
justify-content: center;
}
#circle{
background-color: rgba(9, 13, 57, 0.93);
height: 30px;
width: 30px;
border-radius: 100%;
}
#availability{
background-color: white;
height: 70%;
width: 50%;
margin-left: 60px;
margin-top: 80px;
}
.change{
color:black;
margin:0;
}
strong{
margin: 0;
color: black;
font-size: 20px;
}
#availability>p{
margin: 0;
margin-top: 10px;
margin-bottom: 5px;
}
Your browser information:
User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 OPR/114.0.0.0
Challenge Information:
Build a Cash Register Project - Build a Cash Register