mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-04-11 16:00:12 -04:00
chore(i18n,learn): processed translations (#50057)
This commit is contained in:
@@ -9,7 +9,7 @@ dashedName: step-36
|
||||
|
||||
هذا هو نوعا ما مما تريده، ولكن الآن سيكون من الجيد أن تكون flavor و price على نفس السطر. عناصر `p` هي <dfn>block-level</dfn>، لذا فهي تأخذ كامل عرض العنصر الأساسي (parent element).
|
||||
|
||||
لجعلهم على نفس السطر، تحتاج إلى تطبيق بعض التصميمات على عناصر `p` ، لكي يتصرفون مثل العناصر الـ <dfn>inline</dfn>. أضف سمة `class` مع قيمة `item` إلى عنصر `article` الأول تحت عنوان `Coffee`.
|
||||
To get them on the same line, you need to apply some styling to the `p` elements so they behave more like <dfn>inline</dfn> elements. To do that, start by adding a `class` attribute with the value `item` to the first `article` element under the `Coffee` heading.
|
||||
|
||||
# --hints--
|
||||
|
||||
|
||||
@@ -19,12 +19,6 @@ dashedName: step-24
|
||||
assert(document.querySelectorAll('table')?.[1]?.querySelector('tbody')?.querySelectorAll('tr')?.[3]?.querySelector('th'));
|
||||
```
|
||||
|
||||
Your text `Total Liabilities` should not include period `.`.
|
||||
|
||||
```js
|
||||
assert(document.querySelectorAll('table')?.[1]?.querySelector('tbody')?.querySelectorAll('tr')?.[3]?.querySelector('th')?.innerText !== 'Total Liabilities.');
|
||||
```
|
||||
|
||||
Your `th` element should have the text `Total Liabilities`.
|
||||
|
||||
```js
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
---
|
||||
id: 63ec14d1c216aa063f0be4af
|
||||
title: Step 1
|
||||
challengeType: 0
|
||||
dashedName: step-1
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You will be building a shopping cart application. The HTML and CSS are already provided, but you will need to build the JavaScript to make the page interactive.
|
||||
|
||||
To start, you will need to get some of your elements from the DOM. Start by using `document.getElementById()` to get the`#cart-container`, `#products-container`, and `#dessert-card-container` elements. Store them in variables named `cartContainer`, `productsContainer`, and `dessertCards`, respectively.
|
||||
|
||||
Since these will not change, remember to use `const` to declare them.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `document.getElementById()` to get the `#cart-container` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)cart-container\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#cart-container` element to a variable named `cartContainer`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cartContainer\s*=\s*document\.getElementById\(\s*('|"|`)cart-container\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#products-container` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)products-container\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#products-container` element to a variable named `productsContainer`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+productsContainer\s*=\s*document\.getElementById\(\s*('|"|`)products-container\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#dessert-card-container` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)dessert-card-container\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#dessert-card-container` element to a variable named `dessertCards`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+dessertCards\s*=\s*document\.getElementById\(\s*('|"|`)dessert-card-container\1\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,201 @@
|
||||
---
|
||||
id: 63ec19978a066607e23439f8
|
||||
title: Step 2
|
||||
challengeType: 0
|
||||
dashedName: step-2
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you need to get your two buttons. Continuing the pattern, get the `#cart-btn` and `#clear-cart-btn` elements. Store them in variables named `cartBtn` and `clearCartBtn`, respectively.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `document.getElementById()` to get the `#cart-btn` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)cart-btn\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#cart-btn` element to a variable named `cartBtn`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cartBtn\s*=\s*document\.getElementById\(\s*('|"|`)cart-btn\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#clear-cart-btn` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)clear-cart-btn\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#clear-cart-btn` element to a variable named `clearCartBtn`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+clearCartBtn\s*=\s*document\.getElementById\(\s*('|"|`)clear-cart-btn\1\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,227 @@
|
||||
---
|
||||
id: 63ec1a16f930b108b8a76806
|
||||
title: Step 3
|
||||
challengeType: 0
|
||||
dashedName: step-3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Next is to get your totals. Get the `#total-items`, `#subtotal`, `#taxes`, and `#total` elements. Store them in variables named `totalNumberOfItems`, `cartSubTotal`, `cartTaxes`, and `cartTotal`, respectively.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `document.getElementById()` to get the `#total-items` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)total-items\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#total-items` element to a variable named `totalNumberOfItems`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+totalNumberOfItems\s*=\s*document\.getElementById\(\s*('|"|`)total-items\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#subtotal` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)subtotal\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#subtotal` element to a variable named `cartSubTotal`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cartSubTotal\s*=\s*document\.getElementById\(\s*('|"|`)subtotal\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#taxes` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)taxes\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#taxes` element to a variable named `cartTaxes`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cartTaxes\s*=\s*document\.getElementById\(\s*('|"|`)taxes\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#total` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)total\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#total` element to a variable named `cartTotal`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cartTotal\s*=\s*document\.getElementById\(\s*('|"|`)total\1\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,209 @@
|
||||
---
|
||||
id: 63ec1bbf5584390a7d08d41f
|
||||
title: Step 4
|
||||
challengeType: 0
|
||||
dashedName: step-4
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The last element to get is the `#show-hide-cart` element. Store it in a variable named `showHideCartSpan`.
|
||||
|
||||
Then, use `let` to declare a variable named `isCartShowing` and set it to `false`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `document.getElementById()` to get the `#show-hide-cart` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)show-hide-cart\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#show-hide-cart` element to a variable named `showHideCartSpan`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+showHideCartSpan\s*=\s*document\.getElementById\(\s*('|"|`)show-hide-cart\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `let` to declare a variable named `isCartShowing`.
|
||||
|
||||
```js
|
||||
assert.match(code, /let\s+isCartShowing/);
|
||||
```
|
||||
|
||||
You should set the `isCartShowing` variable to `false`.
|
||||
|
||||
```js
|
||||
assert.match(code, /let\s+isCartShowing\s*=\s*false/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,198 @@
|
||||
---
|
||||
id: 63ec1cb59f2a4c0be5b6dfa0
|
||||
title: Step 5
|
||||
challengeType: 0
|
||||
dashedName: step-5
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
A shopping cart does not serve much purpose without products. Declare a `products` variable and set it to an empty array. Using an array will allow you to store multiple products.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `products` variable with `const`.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+products/);
|
||||
```
|
||||
|
||||
You should set the `products` variable to an empty array.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+products\s*=\s*\[\s*\]/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,226 @@
|
||||
---
|
||||
id: 63ec20a06fff670d37befbd9
|
||||
title: Step 6
|
||||
challengeType: 0
|
||||
dashedName: step-6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You now need to start adding products. Before you do that, you need to consider the structure of your product data. A product will need a unique identifier to distinguish it from other products, a price so people know how much it costs, and a name so people know what they are buying. You should also add a category to each product.
|
||||
|
||||
Add an object to your `products` array. Give this object an `id` property set to the number `1`, a `name` property set to `Vanilla Cupcakes (6 Pack)`, a `price` property set to the number `12.99`, and a `category` property set to `Cupcake`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your products array should have one value.
|
||||
|
||||
```js
|
||||
assert.equal(products.length, 1);
|
||||
```
|
||||
|
||||
Your products array should have an object as its first value.
|
||||
|
||||
```js
|
||||
assert.isObject(products[0]);
|
||||
```
|
||||
|
||||
Your products array should have an object with an `id` property set to the number `1`.
|
||||
|
||||
```js
|
||||
assert.equal(products[0].id, 1);
|
||||
```
|
||||
|
||||
Your products array should have an object with a `name` property set to `Vanilla Cupcakes (6 Pack)`.
|
||||
|
||||
```js
|
||||
assert.equal(products[0].name, 'Vanilla Cupcakes (6 Pack)');
|
||||
```
|
||||
|
||||
Your products array should have an object with a `price` property set to the number `12.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[0].price, 12.99);
|
||||
```
|
||||
|
||||
Your products array should have an object with a `category` property set to `Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[0].category, 'Cupcake');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
--fcc-editable-region--
|
||||
const products = [
|
||||
|
||||
];
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,472 @@
|
||||
---
|
||||
id: 63ec3287b182ec0efe8a3135
|
||||
title: Step 7
|
||||
challengeType: 0
|
||||
dashedName: step-7
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Following that same data structure, add the products from this table (in order) to your `products` array. Increment the `id` for each product, counting up.
|
||||
|
||||
| `name` | `price` | `category` |
|
||||
| ------------------------------ | ------- | ----------- |
|
||||
| `French Macaroon` | `3.99` | `Macaroon` |
|
||||
| `Pumpkin Cupcake` | `3.99` | `Cupcake` |
|
||||
| `Chocolate Cupcake` | `5.99` | `Cupcake` |
|
||||
| `Chocolate Pretzels (4 Pack)` | `10.99` | `Pretzel` |
|
||||
| `Strawberry Ice Cream` | `2.99` | `Ice Cream` |
|
||||
| `Chocolate Macaroons (4 Pack)` | `9.99` | `Macaroon` |
|
||||
| `Strawberry Pretzel` | `4.99` | `Pretzel` |
|
||||
| `Butter Pecan Ice Cream` | `2.99` | `Ice Cream` |
|
||||
| `Rocky Road Ice Cream` | `2.99` | `Ice Cream` |
|
||||
| `Vanilla Macaroons (5 Pack)` | `11.99` | `Macaroon` |
|
||||
| `Lemon Cupcakes (4 Pack)` | `12.99` | `Cupcake` |
|
||||
|
||||
# --hints--
|
||||
|
||||
Your second object in the `products` array should have an `id` property set to the number `2`.
|
||||
|
||||
```js
|
||||
assert.equal(products[1].id, 2);
|
||||
```
|
||||
|
||||
Your second object in the `products` array should have a `name` property set to `French Macaroon`.
|
||||
|
||||
```js
|
||||
assert.equal(products[1].name, 'French Macaroon');
|
||||
```
|
||||
|
||||
Your second object in the `products` array should have a `price` property set to the number `3.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[1].price, 3.99);
|
||||
```
|
||||
|
||||
Your second object in the `products` array should have a `category` property set to `Macaroon`.
|
||||
|
||||
```js
|
||||
assert.equal(products[1].category, 'Macaroon');
|
||||
```
|
||||
|
||||
Your third object in the `products` array should have an `id` property set to the number `3`.
|
||||
|
||||
```js
|
||||
assert.equal(products[2].id, 3);
|
||||
```
|
||||
|
||||
Your third object in the `products` array should have a `name` property set to `Pumpkin Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[2].name, 'Pumpkin Cupcake');
|
||||
```
|
||||
|
||||
Your third object in the `products` array should have a `price` property set to the number `3.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[2].price, 3.99);
|
||||
```
|
||||
|
||||
Your third object in the `products` array should have a `category` property set to `Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[2].category, 'Cupcake');
|
||||
```
|
||||
|
||||
Your fourth object in the `products` array should have an `id` property set to the number `4`.
|
||||
|
||||
```js
|
||||
assert.equal(products[3].id, 4);
|
||||
```
|
||||
|
||||
Your fourth object in the `products` array should have a `name` property set to `Chocolate Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[3].name, 'Chocolate Cupcake');
|
||||
```
|
||||
|
||||
Your fourth object in the `products` array should have a `price` property set to the number `5.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[3].price, 5.99);
|
||||
```
|
||||
|
||||
Your fourth object in the `products` array should have a `category` property set to `Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[3].category, 'Cupcake');
|
||||
```
|
||||
|
||||
Your fifth object in the `products` array should have an `id` property set to the number `5`.
|
||||
|
||||
```js
|
||||
assert.equal(products[4].id, 5);
|
||||
```
|
||||
|
||||
Your fifth object in the `products` array should have a `name` property set to `Chocolate Pretzels (4 Pack)`.
|
||||
|
||||
```js
|
||||
assert.equal(products[4].name, 'Chocolate Pretzels (4 Pack)');
|
||||
```
|
||||
|
||||
Your fifth object in the `products` array should have a `price` property set to the number `10.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[4].price, 10.99);
|
||||
```
|
||||
|
||||
Your fifth object in the `products` array should have a `category` property set to `Pretzel`.
|
||||
|
||||
```js
|
||||
assert.equal(products[4].category, 'Pretzel');
|
||||
```
|
||||
|
||||
Your sixth object in the `products` array should have an `id` property set to the number `6`.
|
||||
|
||||
```js
|
||||
assert.equal(products[5].id, 6);
|
||||
```
|
||||
|
||||
Your sixth object in the `products` array should have a `name` property set to `Strawberry Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[5].name, 'Strawberry Ice Cream');
|
||||
```
|
||||
|
||||
Your sixth object in the `products` array should have a `price` property set to the number `2.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[5].price, 2.99);
|
||||
```
|
||||
|
||||
Your sixth object in the `products` array should have a `category` property set to `Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[5].category, 'Ice Cream');
|
||||
```
|
||||
|
||||
Your seventh object in the `products` array should have an `id` property set to the number `7`.
|
||||
|
||||
```js
|
||||
assert.equal(products[6].id, 7);
|
||||
```
|
||||
|
||||
Your seventh object in the `products` array should have a `name` property set to `Chocolate Macaroons (4 Pack)`.
|
||||
|
||||
```js
|
||||
assert.equal(products[6].name, 'Chocolate Macaroons (4 Pack)');
|
||||
```
|
||||
|
||||
Your seventh object in the `products` array should have a `price` property set to the number `9.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[6].price, 9.99);
|
||||
```
|
||||
|
||||
Your seventh object in the `products` array should have a `category` property set to `Macaroon`.
|
||||
|
||||
```js
|
||||
assert.equal(products[6].category, 'Macaroon');
|
||||
```
|
||||
|
||||
Your eighth object in the `products` array should have an `id` property set to the number `8`.
|
||||
|
||||
```js
|
||||
assert.equal(products[7].id, 8);
|
||||
```
|
||||
|
||||
Your eighth object in the `products` array should have a `name` property set to `Strawberry Pretzel`.
|
||||
|
||||
```js
|
||||
assert.equal(products[7].name, 'Strawberry Pretzel');
|
||||
```
|
||||
|
||||
Your eighth object in the `products` array should have a `price` property set to the number `4.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[7].price, 4.99);
|
||||
```
|
||||
|
||||
Your eighth object in the `products` array should have a `category` property set to `Pretzel`.
|
||||
|
||||
```js
|
||||
assert.equal(products[7].category, 'Pretzel');
|
||||
```
|
||||
|
||||
Your ninth object in the `products` array should have an `id` property set to the number `9`.
|
||||
|
||||
```js
|
||||
assert.equal(products[8].id, 9);
|
||||
```
|
||||
|
||||
Your ninth object in the `products` array should have a `name` property set to `Butter Pecan Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[8].name, 'Butter Pecan Ice Cream');
|
||||
```
|
||||
|
||||
Your ninth object in the `products` array should have a `price` property set to the number `2.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[8].price, 2.99);
|
||||
```
|
||||
|
||||
Your ninth object in the `products` array should have a `category` property set to `Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[8].category, 'Ice Cream');
|
||||
```
|
||||
|
||||
Your tenth object in the `products` array should have an `id` property set to the number `10`.
|
||||
|
||||
```js
|
||||
assert.equal(products[9].id, 10);
|
||||
```
|
||||
|
||||
Your tenth object in the `products` array should have a `name` property set to `Rocky Road Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[9].name, 'Rocky Road Ice Cream');
|
||||
```
|
||||
|
||||
Your tenth object in the `products` array should have a `price` property set to the number `2.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[9].price, 2.99);
|
||||
```
|
||||
|
||||
Your tenth object in the `products` array should have a `category` property set to `Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[9].category, 'Ice Cream');
|
||||
```
|
||||
|
||||
Your eleventh object in the `products` array should have an `id` property set to the number `11`.
|
||||
|
||||
```js
|
||||
assert.equal(products[10].id, 11);
|
||||
```
|
||||
|
||||
Your eleventh object in the `products` array should have a `name` property set to `Vanilla Macaroons (5 Pack)`.
|
||||
|
||||
```js
|
||||
assert.equal(products[10].name, 'Vanilla Macaroons (5 Pack)');
|
||||
```
|
||||
|
||||
Your eleventh object in the `products` array should have a `price` property set to the number `11.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[10].price, 11.99);
|
||||
```
|
||||
|
||||
Your eleventh object in the `products` array should have a `category` property set to `Macaroon`.
|
||||
|
||||
```js
|
||||
assert.equal(products[10].category, 'Macaroon');
|
||||
```
|
||||
|
||||
Your twelfth object in the `products` array should have an `id` property set to the number `12`.
|
||||
|
||||
```js
|
||||
assert.equal(products[11].id, 12);
|
||||
```
|
||||
|
||||
Your twelfth object in the `products` array should have a `name` property set to `Lemon Cupcakes (4 Pack)`.
|
||||
|
||||
```js
|
||||
assert.equal(products[11].name, 'Lemon Cupcakes (4 Pack)');
|
||||
```
|
||||
|
||||
Your twelfth object in the `products` array should have a `price` property set to the number `12.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[11].price, 12.99);
|
||||
```
|
||||
|
||||
Your twelfth object in the `products` array should have a `category` property set to `Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[11].category, 'Cupcake');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
--fcc-editable-region--
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
|
||||
];
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,281 @@
|
||||
---
|
||||
id: 63ec3427fc3e9214c9ed2a14
|
||||
title: Step 8
|
||||
challengeType: 0
|
||||
dashedName: step-8
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that you have your list of products, you can use JavaScript to insert them into the HTML. With this approach, if you decide to add more products, the HTML will automatically reflect that.
|
||||
|
||||
Start by calling the `.forEach` method of your `products` array. Use arrow syntax to create an empty callback function.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call the `.forEach` method of your `products` array.
|
||||
|
||||
```js
|
||||
assert.match(code, /products\.forEach\(/);
|
||||
```
|
||||
|
||||
You should use arrow syntax to create an empty callback function.
|
||||
|
||||
```js
|
||||
assert.match(code, /\(\s*\)\s*=>\s*\{\s*\}/)
|
||||
```
|
||||
|
||||
You should pass your empty callback function to the `.forEach` method.
|
||||
|
||||
```js
|
||||
assert.match(code, /products\.forEach\(\s*\(\s*\)\s*=>\s*\{\s*\}\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,277 @@
|
||||
---
|
||||
id: 63ec36f6133df7160be3ec66
|
||||
title: Step 9
|
||||
challengeType: 0
|
||||
dashedName: step-9
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Remember that you can use destructuring to extract multiple values from an array or object in a single statement.
|
||||
|
||||
For the first parameter of your callback function, destructure the `name`, `id`, `price`, and `category` properties from the object passed in.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use destructuring to declare `name`, `id`, `price`, and `category` parameters. For this test, order matters.
|
||||
|
||||
```js
|
||||
assert.match(code, /\{\s*name\s*,\s*id\s*,\s*price\s*,\s*category\s*\}/);
|
||||
```
|
||||
|
||||
Your destructuring should be the first parameter of the callback function.
|
||||
|
||||
```js
|
||||
assert.match(code, /products.forEach\(\s*\(\s*\{\s*name\s*,\s*id\s*,\s*price\s*,\s*category\s*\}\s*\)\s*=>/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
products.forEach(
|
||||
() => {}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,283 @@
|
||||
---
|
||||
id: 63ec47b454495519739486a7
|
||||
title: Step 10
|
||||
challengeType: 0
|
||||
dashedName: step-10
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need to display the available products in your HTML. Start by using the addition assignment operator to add an empty template literal string to the `innerHTML` property of the `dessertCards` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use access the `innerHTML` property of the `dessertCards` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /dessertCards\.innerHTML/);
|
||||
```
|
||||
|
||||
You should use the addition assignment operator on the `innerHTML` property.
|
||||
|
||||
```js
|
||||
assert.match(code, /dessertCards\.innerHTML\s*\+=\s*/);
|
||||
```
|
||||
|
||||
You should add an empty template literal string to the `innerHTML` property.
|
||||
|
||||
```js
|
||||
assert.match(code, /dessertCards\.innerHTML\s*\+=\s*`\s*`/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,297 @@
|
||||
---
|
||||
id: 63ee5d38a5d29d0696f8d820
|
||||
title: Step 11
|
||||
challengeType: 0
|
||||
dashedName: step-11
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In your template literal, create a `div` element with a class of `dessert-card`. In that `div`, create an `h2` element and give it the text of the `name` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `div` element.
|
||||
|
||||
```js
|
||||
assert.isAtLeast(document.querySelectorAll('div')?.length, 12);
|
||||
```
|
||||
|
||||
Your `div` element should have a class of `dessert-card`.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelectorAll('.dessert-card')?.length, 12);
|
||||
```
|
||||
|
||||
You should create an `h2` element.
|
||||
|
||||
```js
|
||||
assert.isAtLeast(document.querySelectorAll('h2')?.length, 12);
|
||||
```
|
||||
|
||||
Your `h2` element should have the text of the `name` variable.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelectorAll('h2')[0]?.textContent, 'Vanilla Cupcakes (6 Pack)');
|
||||
```
|
||||
|
||||
Your `h2` element should be inside the `div` element.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelectorAll('div h2')?.length, 12);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
|
||||
`;
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,309 @@
|
||||
---
|
||||
id: 63ee5d8f9e7168076e932fe2
|
||||
title: Step 12
|
||||
challengeType: 0
|
||||
dashedName: step-12
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
After your `h2` element, create two `p` elements. Give the first a `class` of `dessert-price`, and the text of the `price` variable with a dollar sign in front of it. Give the second a `class` of `product-category`, and the text `Category:` followed by the value of the `category` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create two `p` elements.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children.length, 3);
|
||||
assert.equal(document.querySelector('.dessert-card')?.querySelectorAll('p')?.length, 2)
|
||||
```
|
||||
|
||||
Your `p` elements should come after your `h2` element.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[0].tagName, 'H2');
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[1].tagName, 'P');
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[2].tagName, 'P');
|
||||
```
|
||||
|
||||
Your first `p` element should have a `class` of `dessert-price`.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[1].className, 'dessert-price');
|
||||
```
|
||||
|
||||
Your first `p` element should have the text of the `price` variable with a dollar sign in front of it.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[1].textContent, '$12.99');
|
||||
```
|
||||
|
||||
Your second `p` element should have a `class` of `product-category`.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[2].className, 'product-category');
|
||||
```
|
||||
|
||||
Your second `p` element should have the text `Category:` followed by the value of the `category` variable.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[2].textContent, 'Category: Cupcake');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,304 @@
|
||||
---
|
||||
id: 63ee5e0f08e82208364c4128
|
||||
title: Step 13
|
||||
challengeType: 0
|
||||
dashedName: step-13
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Finally, after your `p` elements, create a `button` element. Give it an `id` set to the value of the `id` variable, a `class` of `btn add-to-cart-btn`, and use `Add to cart` for the text.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `button` element.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelectorAll('.dessert-card button')?.length, 12);
|
||||
```
|
||||
|
||||
Your `button` element should come after your `p` elements.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card button')?.previousElementSibling?.tagName, 'P');
|
||||
assert.isNull(document.querySelector('.dessert-card button')?.nextElementSibling);
|
||||
```
|
||||
|
||||
Your `button` element should have an `id` set to the value of the `id` variable.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card button')?.id, '1');
|
||||
```
|
||||
|
||||
Your `button` element should have a `class` of `btn add-to-cart-btn`.
|
||||
|
||||
```js
|
||||
assert.include(document.querySelector('.dessert-card button')?.className, 'btn');
|
||||
assert.include(document.querySelector('.dessert-card button')?.className, 'add-to-cart-btn');
|
||||
```
|
||||
|
||||
Your `button` element should have the text `Add to cart`.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card button')?.textContent?.trim(), 'Add to cart');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,303 @@
|
||||
---
|
||||
id: 63ee5ea8be892e0955ab346c
|
||||
title: Step 14
|
||||
challengeType: 0
|
||||
dashedName: step-14
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You are already familiar with an HTML `class`, but JavaScript also has a <dfn>class</dfn>. In JavaScript, a class is like a blueprint for creating objects. It allows you to define a set of properties and methods, and instantiate (or create) new objects with those properties and methods.
|
||||
|
||||
The `class` keyword is used to declare a class. Here is an example of declaring a `Computer` class:
|
||||
|
||||
```js
|
||||
class Computer {};
|
||||
```
|
||||
|
||||
Declare a `ShoppingCart` class.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `ShoppingCart` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /ShoppingCart/);
|
||||
```
|
||||
|
||||
You should use the `class` keyword to declare a `ShoppingCart` class.
|
||||
|
||||
```js
|
||||
assert.match(code, /class\s+ShoppingCart\s*/);
|
||||
```
|
||||
|
||||
Your `ShoppingCart` class should be empty.
|
||||
|
||||
```js
|
||||
assert.match(code, /class\s+ShoppingCart\s*\{\s*\}/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,300 @@
|
||||
---
|
||||
id: 63ee5fc113bcb20a5db9214b
|
||||
title: Step 15
|
||||
challengeType: 0
|
||||
dashedName: step-15
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Classes have a special `constructor` method, which is called when a new instance of the class is created. The `constructor` method is a great place to initialize properties of the class. Here is an example of a class with a `constructor` method:
|
||||
|
||||
```js
|
||||
class Computer {
|
||||
constructor() {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Add an empty `constructor` method to the `ShoppingCart` class.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add a `constructor` method to the `ShoppingCart` class.
|
||||
|
||||
```js
|
||||
assert.match(code, /class\s+ShoppingCart\s*\{\s*constructor\(\s*\)\s*/)
|
||||
```
|
||||
|
||||
Your `constructor` method should be empty.
|
||||
|
||||
```js
|
||||
assert.match(code, /class\s+ShoppingCart\s*\{\s*constructor\(\s*\)\s*\{\s*\}\s*\}/)
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
class ShoppingCart {
|
||||
|
||||
};
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,316 @@
|
||||
---
|
||||
id: 63ee611d478dca0b77f6a393
|
||||
title: Step 16
|
||||
challengeType: 0
|
||||
dashedName: step-16
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `this` keyword in JavaScript is used to refer to the current object. Depending on where `this` is used, what it references changes. In the case of a class, it refers to the instance of the object being constructed. You can use the `this` keyword to set the properties of the object being instantiated. Here is an example:
|
||||
|
||||
```js
|
||||
class Computer {
|
||||
constructor() {
|
||||
this.ram = 16;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In your constructor, use the `this` keyword to set the `items` property to an empty array. Also, set the `total` property to `0`, and the `taxRate` property to `8.25`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `this` keyword to set the `items` property of your class to an empty array.
|
||||
|
||||
```js
|
||||
assert.match(code, /this\.items/);
|
||||
const cart = new ShoppingCart();
|
||||
assert.isArray(cart.items);
|
||||
assert.isEmpty(cart.items);
|
||||
```
|
||||
|
||||
You should use the `this` keyword to set the `total` property of your class to `0`.
|
||||
|
||||
```js
|
||||
assert.match(code, /this\.total/);
|
||||
const cart = new ShoppingCart();
|
||||
assert.equal(cart.total, 0);
|
||||
```
|
||||
|
||||
You should use the `this` keyword to set the `taxRate` property of your class to `8.25`.
|
||||
|
||||
```js
|
||||
assert.match(code, /this\.taxRate/);
|
||||
const cart = new ShoppingCart();
|
||||
assert.equal(cart.taxRate, 8.25);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
|
||||
}
|
||||
};
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,321 @@
|
||||
---
|
||||
id: 63ee7c664f9b65137d925c8a
|
||||
title: Step 17
|
||||
challengeType: 0
|
||||
dashedName: step-17
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Your `ShoppingCart` class needs the ability to add items. Create an empty `addItem` method, which takes two parameters: `id` and `products`. Creating a method might look like this:
|
||||
|
||||
```js
|
||||
class Computer {
|
||||
constructor() {
|
||||
this.ram = 16;
|
||||
}
|
||||
|
||||
addRam(amount) {
|
||||
this.ram += amount;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The first parameter, `id`, is the `id` of the product the user has added to their cart. The second parameter, `products`, is an array of product objects. By using a parameter instead of directly referencing your existing `products` array, this method will be more flexible if you wanted to add additional product lists in the future.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `ShoppingCart` class should have an `addItem` method.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.isFunction(cart.addItem);
|
||||
```
|
||||
|
||||
Your `addItem` method should take two parameters: `id` and `products`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /\(\s*id\s*,\s*products\s*\)/);
|
||||
```
|
||||
|
||||
Your `addItem` method should be empty.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /\(\s*id\s*,\s*products\s*\)\s*\{\s*\}/);
|
||||
```
|
||||
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,331 @@
|
||||
---
|
||||
id: 63eea5cea403a81a68ae493c
|
||||
title: Step 18
|
||||
challengeType: 0
|
||||
dashedName: step-18
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need to find the product that the user is adding to the cart. Remember that arrays have a `.find()` method. In your `addItem` function, declare a `product` variable, and assign it the value of calling the `.find()` method on the `products` array.
|
||||
|
||||
For the callback to `.find()`, pass a function that takes a single parameter `item`, and returns whether the `id` property of `item` is strictly equal to the `id` parameter passed to `addItem`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `product` variable in your `addItem` function.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /product\s*=/);
|
||||
```
|
||||
|
||||
You should call the `.find()` method on your `products` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /products\.find\(/);
|
||||
```
|
||||
|
||||
You should pass a callback function to the `.find()` method.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /products\.find\(\s*function\s*\(/);
|
||||
```
|
||||
|
||||
The callback function should take a single parameter.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /products\.find\(\s*function\s*\(\s*item\s*\)/);
|
||||
```
|
||||
|
||||
The callback function should return whether the `id` property of `item` is strictly equal to the `id` parameter passed to `addItem`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /products\.find\(\s*function\s*\(\s*item\s*\)\s*\{\s*return\s+item\.id\s*===\s*id\s*;?\s*\}/);
|
||||
```
|
||||
|
||||
You should assign the value of the `.find()` method to the `product` variable.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /product\s*=\s*products\.find\(/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,309 @@
|
||||
---
|
||||
id: 63eea817673c8e1c22927fa6
|
||||
title: Step 19
|
||||
challengeType: 0
|
||||
dashedName: step-19
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Use `const` and destructuring to extract `name` and `price` variables from `product`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use destructuring to get the `name` and `price` variables.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /\{\s*name\s*,\s*price\s*\}/);
|
||||
```
|
||||
|
||||
You should use `const` to declare the `name` and `price` variables.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s*\{\s*name\s*,\s*price\s*\}/);
|
||||
```
|
||||
|
||||
You should use destructuring to get the `name` and `price` variables from `product`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s*\{\s*name\s*,\s*price\s*\}\s*=\s*product;?\b/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,311 @@
|
||||
---
|
||||
id: 63eea8e1e143ae1d098c8c9d
|
||||
title: Step 20
|
||||
challengeType: 0
|
||||
dashedName: step-20
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you need to push the `product` into the cart's `items` array. Remember to use the `this` keyword.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call the `push` method on the `items` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /items\.push\(/);
|
||||
```
|
||||
|
||||
Remember you need to use the `this` keyword to access the `items` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /this\.items\.push\(/);
|
||||
```
|
||||
|
||||
You should `push` the `product` variable to the `items` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
assert.deepEqual(cart.items, [products[0]]);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,312 @@
|
||||
---
|
||||
id: 63eeb8e86becbf1e75c2cb0d
|
||||
title: Step 21
|
||||
challengeType: 0
|
||||
dashedName: step-21
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You now need a total count of each product that the user has in the cart. Declare a `totalCountPerProduct` variable, and assign it an empty object.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `totalCountPerProduct` variable in your `addItem` function.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\s*=/);
|
||||
```
|
||||
|
||||
You should use `const` to declare `totalCountPerProduct`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s+totalCountPerProduct\s*=/);
|
||||
```
|
||||
|
||||
You should assign an empty object to `totalCountPerProduct`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s+totalCountPerProduct\s*=\s*\{\s*\}/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,327 @@
|
||||
---
|
||||
id: 63eedebb0ec0231ff1cede1a
|
||||
title: Step 22
|
||||
challengeType: 0
|
||||
dashedName: step-22
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Use the `.forEach()` method to loop through the `items` array. Pass an empty callback function that takes a single parameter `dessert`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `.forEach()` method on your `items` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /items\.forEach\(/);
|
||||
```
|
||||
|
||||
Remember to use the `this` keyword to access the `items` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /this\.items\.forEach\(/);
|
||||
```
|
||||
|
||||
You should pass a callback function to the `.forEach()` method.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /this\.items\.forEach\(\s*function\s*\(/);
|
||||
```
|
||||
|
||||
Your callback function should take a single parameter.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /this\.items\.forEach\(\s*function\s*\(\s*dessert\s*\)/);
|
||||
```
|
||||
|
||||
Your callback function should be empty.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /this\.items\.forEach\(\s*function\s*\(\s*dessert\s*\)\s*\{\s*\}/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,323 @@
|
||||
---
|
||||
id: 63efdbc22a0c56070beabed7
|
||||
title: Step 23
|
||||
challengeType: 0
|
||||
dashedName: step-23
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In your `forEach` callback, you need to update the `totalCountPerProduct` object. Using the `id` of the current `dessert` as your property, update the value of the property to be the current value plus one. Do not use the addition assignment operator for this.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use dot notation to access the `id` property of `dessert`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /dessert\.id/);
|
||||
```
|
||||
|
||||
You should use bracket notation to access the property of `totalCountPerProduct` that corresponds to `dessert.id`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]/);
|
||||
```
|
||||
|
||||
You should use the assignment operator to update the value of the property of `totalCountPerProduct` that corresponds to `dessert.id`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=/);
|
||||
```
|
||||
|
||||
You should update the value of `totalCountPerProduct` to be the current value plus one.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=\s*totalCountPerProduct\[\s*dessert\.id\s*\]\s*\+\s*1/);
|
||||
```
|
||||
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
|
||||
})
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,324 @@
|
||||
---
|
||||
id: 63efe370bbfc4a08d500118e
|
||||
title: Step 24
|
||||
challengeType: 0
|
||||
dashedName: step-24
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You now have a small bug. When you try to access a property of an object and the property doesn't exist, you get `undefined`. This means if the dessert isn't already present in the `totalCountPerProduct` object, you end up trying to add `1` to `undefined`, which results in `NaN`.
|
||||
|
||||
To fix this, you can use the `||` operator to set the value to `0` if it doesn't exist. Wrap your right-hand `totalCountPerProduct[data.id]` in parentheses, and add `|| 0` to the end of the expression.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should wrap your right-hand `totalCountPerProduct[data.id]` in parentheses.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=\s*\(\s*totalCountPerProduct\[\s*dessert\.id\s*\]/);
|
||||
```
|
||||
|
||||
You should use the `||` operator.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=\s*\(\s*totalCountPerProduct\[\s*dessert\.id\s*\]\s*\|\|\s*/);
|
||||
```
|
||||
|
||||
You should use `0` as your fallback value.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=\s*\(\s*totalCountPerProduct\[\s*dessert\.id\s*\]\s*\|\|\s*0\s*\)/);
|
||||
```
|
||||
|
||||
You should still add `1` to the value.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=\s*\(\s*totalCountPerProduct\[\s*dessert\.id\s*\]\s*\|\|\s*0\s*\)\s*\+\s*1/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = totalCountPerProduct[dessert.id] + 1;
|
||||
})
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,317 @@
|
||||
---
|
||||
id: 63eff02f00e69a0b2ac10b43
|
||||
title: Step 25
|
||||
challengeType: 0
|
||||
dashedName: step-25
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you need to get prepared to update the display with the new product the user added. Declare a `currentProductCount` variable, and assign it the value of the `totalCountPerProduct` object's property matching the `id` of `product`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `currentProductCount` variable in your `addItem` function.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*=/);
|
||||
```
|
||||
|
||||
You should use `const` to declare `currentProductCount`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s+currentProductCount\s*=/);
|
||||
```
|
||||
|
||||
You should assign the value of `totalCountPerProduct[product.id]` to `currentProductCount`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*=\s*totalCountPerProduct\[product\.id\]/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,336 @@
|
||||
---
|
||||
id: 63eff98ffb1d5a0d24ec79cb
|
||||
title: Step 26
|
||||
challengeType: 0
|
||||
dashedName: step-26
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You haven't written the code to generate the HTML yet, but if a product has already been added to the user's cart then there will be a matching element which you'll need.
|
||||
|
||||
Use `.getElementById()` to get the matching element - you'll be setting the `id` value to `product-count-for-id${product.id}`, so use a template literal to query that value.
|
||||
|
||||
Assign your query to a `currentProductCountSpan` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `currentProductCountSpan` variable.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCountSpan\s*=/);
|
||||
```
|
||||
|
||||
You should use `const` to declare `currentProductCountSpan`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s+currentProductCountSpan\s*=/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the matching element.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /document\.getElementById\(/);
|
||||
```
|
||||
|
||||
You should use a template literal to query the `id` value.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /document\.getElementById\(\s*`product-count-for-id\$\{(product\.)?id\}`\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the value of `document.getElementById()` to `currentProductCountSpan`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCountSpan\s*=\s*document\.getElementById\(/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,327 @@
|
||||
---
|
||||
id: 63effe558c87a70e7072e447
|
||||
title: Step 27
|
||||
challengeType: 0
|
||||
dashedName: step-27
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The behaviour of the `addItem` method needs to change if the product is already in the cart or not. Create a ternary that checks if the current product is already in the cart. Use `undefined` for both the truthy and falsy expressions to avoid a syntax error.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should check if `currentProductCount` is greater than `1`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*>\s*1/);
|
||||
```
|
||||
|
||||
You should use a ternary operator with your `currentProductCount > 1` condition.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*>\s*1\s*\?/);
|
||||
```
|
||||
|
||||
You should use `undefined` as the truthy expression.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*>\s*1\s*\?\s*undefined/);
|
||||
```
|
||||
|
||||
You should use `undefined` as the falsy expression.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*>\s*1\s*\?\s*undefined\s*:\s*undefined/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,320 @@
|
||||
---
|
||||
id: 63f0165121a9181342d5bc66
|
||||
title: Step 28
|
||||
challengeType: 0
|
||||
dashedName: step-28
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
For your truthy expression, removing the `undefined`, you need to update the `textContent` of the `currentProductCountSpan` to be the `currentProductCount` followed by an `x`. Use a template literal to do so.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should remove the `undefined` from your truthy expression.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.notMatch(cart.addItem.toString(), /currentProductCount\s*>\s*1\s*\?\s*undefined/);
|
||||
```
|
||||
|
||||
You should access the `textContent` property of `currentProductCountSpan`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*>\s*1\s*\?\s*currentProductCountSpan\.textContent/);
|
||||
```
|
||||
|
||||
You should use template literal syntax to update the `textContent` to be `${currentProductCount}x`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /currentProductCount\s*>\s*1\s*\?\s*currentProductCountSpan\.textContent\s*=\s*`\$\{currentProductCount\}x`\s*:/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1 ? undefined : undefined;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,345 @@
|
||||
---
|
||||
id: 63f017b4ad028a148eb713c0
|
||||
title: Step 29
|
||||
challengeType: 0
|
||||
dashedName: step-29
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
For your falsy expression, you'll need to add new HTML to your `productsContainer`. Start by removing the `undefined`, then use the addition assignment operator and template literal syntax to add a `div` with the `class` set to `product` and the `id` set to `dessert${id}` to the `innerHTML` property of the `productsContainer`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should remove the `undefined` from your falsy expression.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.notMatch(cart.addItem.toString(), /undefined/);
|
||||
```
|
||||
|
||||
You should use the addition assignment operator to add HTML to the `productsContainer`. Remember that HTML goes in the `innerHTML` property.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /productsContainer\.innerHTML\s*\+=\s*/);
|
||||
```
|
||||
|
||||
You should use template literal syntax to add HTML to the `productsContainer`.
|
||||
|
||||
```js
|
||||
assert.match(code, /productsContainer\.innerHTML\s*\+=\s*`/);
|
||||
```
|
||||
|
||||
You should add a `div` to the `productsContainer`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
assert.equal(productsContainer.children?.[0]?.tagName, "DIV");
|
||||
```
|
||||
|
||||
Your `div` should have the `class` set to `product`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
assert.equal(productsContainer.children?.[0]?.className, "product");
|
||||
```
|
||||
|
||||
Your `div` should have the `id` set to `dessert${id}`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
assert.equal(productsContainer.children?.[0]?.id, "dessert1");
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: undefined;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,325 @@
|
||||
---
|
||||
id: 63f01861f813e01564c95315
|
||||
title: Step 30
|
||||
challengeType: 0
|
||||
dashedName: step-30
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Inside your `div`, add two `p` elements. Set the text of the second `p` element to be the value of the `price` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add two `p` elements inside your `div` element.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
assert.equal(div?.children.length, 2);
|
||||
assert.equal(div?.children[0].tagName, 'P');
|
||||
assert.equal(div?.children[1].tagName, 'P');
|
||||
```
|
||||
|
||||
Your second `p` element should have the text of the `price` variable.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
assert.equal(div?.children[1].textContent, '12.99');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,349 @@
|
||||
---
|
||||
id: 63f018f04e487e164dc27bd9
|
||||
title: Step 31
|
||||
challengeType: 0
|
||||
dashedName: step-31
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In your first `p` element, add a `span` element. Give the `span` a class of `product-count` and an `id` of `product-count-for-id${id}`. Then, after the span, give your `p` element the text of the `name` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your first `p` element should have a `span` element.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
const p = div.querySelector('p');
|
||||
assert.equal(p.children.length, 1);
|
||||
assert.equal(p.children[0].tagName, 'SPAN');
|
||||
```
|
||||
|
||||
Your `span` element should have a `class` of `product-count`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
const p = div.querySelector('p');
|
||||
assert.equal(p.children[0].className, 'product-count');
|
||||
```
|
||||
|
||||
Your `span` element should have an `id` of `product-count-for-id${id}`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
const p = div.querySelector('p');
|
||||
assert.equal(p.children[0].id, 'product-count-for-id1');
|
||||
```
|
||||
|
||||
Your first `p` element should have the text of the `name` variable. This should be outside the span.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
const p = div.querySelector('p');
|
||||
assert.equal(p.innerText.trim(), 'Vanilla Cupcakes (6 Pack)');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,334 @@
|
||||
---
|
||||
id: 63f01c9791a0aa1751c73760
|
||||
title: Step 32
|
||||
challengeType: 0
|
||||
dashedName: step-32
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
There is still more functionality that your `ShoppingCart` class needs, but first you need to be able to test the code you have currently written. You'll need to <dfn>instantiate</dfn> a new `ShoppingCart` object and assign it to a variable. Here is an example of instantiating the `Computer` class from earlier examples:
|
||||
|
||||
```js
|
||||
const myComputer = new Computer();
|
||||
```
|
||||
|
||||
Declare a `cart` variable, and assign it a new `ShoppingCart` object. Note the use of the `new` keyword when instantiating the object.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `const` to declare a `cart` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cart\s*=/);
|
||||
```
|
||||
|
||||
You should use the `new` keyword to instantiate a new `ShoppingCart` object.
|
||||
|
||||
```js
|
||||
assert.match(code, /new\s+ShoppingCart\s*\(\s*\)/);
|
||||
```
|
||||
|
||||
You should assign your new `ShoppingCart` object to the `cart` variable.
|
||||
|
||||
```js
|
||||
assert.isTrue(cart instanceof ShoppingCart);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,335 @@
|
||||
---
|
||||
id: 63f0224ceb16dc196d2c860a
|
||||
title: Step 33
|
||||
challengeType: 0
|
||||
dashedName: step-33
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need to get all of the `Add to cart` buttons that you added to the DOM earlier. Declare an `addToCartBtns` variable, and assign it the value of calling the `getElementsByClassName()` method on the `document` object, passing in the string `add-to-cart-btn`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `const` to declare your `addToCartBtns` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+addToCartBtns\s*=/);
|
||||
```
|
||||
|
||||
You should call the `getElementsByClassName()` method on the `document` object.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\s*\.\s*getElementsByClassName\s*\(/);
|
||||
```
|
||||
|
||||
You should pass the string `add-to-cart-btn` to the `getElementsByClassName()` method.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\s*\.\s*getElementsByClassName\s*\(\s*('|"|`)add-to-cart-btn\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the value returned by the `getElementsByClassName()` method to the `addToCartBtns` variable.
|
||||
|
||||
```js
|
||||
assert.deepEqual(addToCartBtns, document.getElementsByClassName('add-to-cart-btn'));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,339 @@
|
||||
---
|
||||
id: 63f026d041bc6c1a3d5cba0f
|
||||
title: Step 34
|
||||
challengeType: 0
|
||||
dashedName: step-34
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need to iterate through the buttons in your `addToCartBtns` variable. However, `.getElementsByClassName()` returns a Collection, which does not have a `forEach` method.
|
||||
|
||||
Use the spread operator on the `addToCartBtns` variable to convert it into an array. Then, use the `forEach` method to iterate through the array. Do not pass a callback function yet.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the spread operator on the `addToCartBtns` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /\.\.\.addToCartBtns/);
|
||||
```
|
||||
|
||||
You should spread the `addToCartBtns` variable into an array.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]/);
|
||||
```
|
||||
|
||||
You should use the `forEach` method on the array you created.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(/);
|
||||
```
|
||||
|
||||
You should not pass a callback function to the `forEach` method.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,339 @@
|
||||
---
|
||||
id: 63f0284532742c1b26c7a052
|
||||
title: Step 35
|
||||
challengeType: 0
|
||||
dashedName: step-35
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Add your callback function to the `forEach` method. It should take a `btn` parameter. Then, in the callback, add an event listener to the `btn`. The event listener should listen for a `click` event, and should take another callback with an `event` parameter. The second callback should be empty.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use arrow syntax to add a callback function to the `forEach` method which takes a `btn` parameter.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(\s*\(?\s*btn\s*\)?\s*=>\s*\{/);
|
||||
```
|
||||
|
||||
You should add an event listener to the `btn` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(\s*\(?\s*btn\s*\)?\s*=>\s*\{\s*btn\s*\.\s*addEventListener\s*\(/);
|
||||
```
|
||||
|
||||
You should listen for a `click` event on the `btn` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(\s*\(?\s*btn\s*\)?\s*=>\s*\{\s*btn\s*\.\s*addEventListener\s*\(\s*('|"|`)click\1\s*,\s*/);
|
||||
```
|
||||
|
||||
You should add an empty callback function to the event listener. Remember to give it an `event` parameter.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(\s*\(?\s*btn\s*\)?\s*=>\s*\{\s*btn\s*\.\s*addEventListener\s*\(\s*('|"|`)click\1\s*,\s*\(\s*event\s*\)\s*=>\s*\{\s*\}\s*\)\s*\s*\}\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
--fcc-editable-region--
|
||||
[...addToCartBtns].forEach(
|
||||
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,339 @@
|
||||
---
|
||||
id: 63f0289df84a581bbdbd29b7
|
||||
title: Step 36
|
||||
challengeType: 0
|
||||
dashedName: step-36
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In your event listener callback, call the `.addItem()` method of your `cart` object, and pass in the `event.target.id`. Remember that the `id` here will be a string, so you need to convert it to a number.
|
||||
|
||||
Pass your `products` array as the second argument.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your event listener callback should call the `.addItem()` method of your `cart` object.
|
||||
|
||||
```js
|
||||
assert.match(code, /cart\.addItem\(/);
|
||||
```
|
||||
|
||||
Your `.addItem()` method should be called with the `event.target.id` as the first argument. Remember to convert the `id` to a number using `Number()`.
|
||||
|
||||
```js
|
||||
assert.match(code, /cart\.addItem\(\s*Number\(\s*event\.target\.id\s*\)\s*/);
|
||||
```
|
||||
|
||||
Your `.addItem()` method should be called with the `products` array as the second argument.
|
||||
|
||||
```js
|
||||
assert.match(code, /cart\.addItem\(\s*Number\(\s*event\.target\.id\s*\)\s*,\s*products\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
--fcc-editable-region--
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
|
||||
})
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,350 @@
|
||||
---
|
||||
id: 63f0295e673b661ccb299e8a
|
||||
title: Step 41
|
||||
challengeType: 0
|
||||
dashedName: step-41
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need a way to access the total number of items in the cart. The best way to do this is to add another method to your `ShoppingCart` class, rather than accessing the `items` array directly.
|
||||
|
||||
Add a `getCounts` method to the `ShoppingCart` class. It should return the number of items in the `items` array.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `ShoppingCart` class should have a `getCounts` method.
|
||||
|
||||
```js
|
||||
assert.isFunction(cart.getCounts);
|
||||
```
|
||||
|
||||
Remember to use the `this` keyword to access the `items` array.
|
||||
|
||||
```js
|
||||
const afterCounts = code.split('getCounts')[1];
|
||||
assert.match(afterCounts, /this\s*\.\s*items\s*\.\s*length/);
|
||||
```
|
||||
|
||||
Your `getCounts` method should return the number of items in the `items` array.
|
||||
|
||||
```js
|
||||
assert.equal(cart.getCounts(), 0);
|
||||
cart.addItem(1, products);
|
||||
assert.equal(cart.getCounts(), 1);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,342 @@
|
||||
---
|
||||
id: 63f029b96b9e9e1df93be951
|
||||
title: Step 42
|
||||
challengeType: 0
|
||||
dashedName: step-42
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you can update the total number of items on the webpage. Assign the value of your `cart` object's `.getCounts()` method to the `textContent` of the `totalNumberOfItems` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should access the `textContent` property of the `totalNumberOfItems` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /totalNumberOfItems\s*\.\s*textContent/)
|
||||
```
|
||||
|
||||
You should assign the value of your `cart` object's `.getCounts()` method to the `textContent` property of the `totalNumberOfItems` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /totalNumberOfItems\s*\.\s*textContent\s*=\s*cart\s*\.\s*getCounts\(\s*\)/)
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
--fcc-editable-region--
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
|
||||
})
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,377 @@
|
||||
---
|
||||
id: 63f02a4ef92d711ec1ff618c
|
||||
title: Step 43
|
||||
challengeType: 0
|
||||
dashedName: step-43
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You also need to update the total price of the cart when the user adds an item. Create a `calculateTotal` method in the `ShoppingCart` class.
|
||||
|
||||
In that method, declare a `subTotal` variable and use the `reduce` method on the `items` array to calculate the sum of the `price` property of each item in the array. Use `total` and `item` as the parameters for your callback.
|
||||
|
||||
Remember to set your initial value in the `reduce` method.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `calculateTotal` method in the `ShoppingCart` class.
|
||||
|
||||
```js
|
||||
assert.isFunction(cart.calculateTotal);
|
||||
```
|
||||
|
||||
Your `calculateTotal` method should have a `subTotal` variable declared with `const`.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /const\s+subTotal\s*=/);
|
||||
```
|
||||
|
||||
Your `calculateTotal` method should use the `reduce` method on the `items` array.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /this\s*\.\s*items\s*\.\s*reduce/);
|
||||
```
|
||||
|
||||
Your `reduce` callback should use `total` and `item` as the first and second parameter. Remember to use arrow function syntax.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /\(\s*total\s*,\s*item\s*\)\s*=>/);
|
||||
```
|
||||
|
||||
Your `reduce` callback should return the sum of `total` and `item.price`. Use an implicit return.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /\(\s*total\s*,\s*item\s*\)\s*=>\s*total\s*\+\s*item\.price/);
|
||||
```
|
||||
|
||||
Your `reduce` call should have an initial value of `0`.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /this\s*\.\s*items\s*\.\s*reduce\s*\(\s*\(total,\s*item\)\s*=>\s*total\s*\+\s*item\.price\s*,\s*0\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,348 @@
|
||||
---
|
||||
id: 63f02b22cce1c11fe9604381
|
||||
title: Step 44
|
||||
challengeType: 0
|
||||
dashedName: step-44
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Part of the total cost will include the tax, so you need to calculate that as well. Create a `calculateTaxes` method in the `ShoppingCart` class. This method should take an `amount` parameter.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `calculateTaxes` method in the `ShoppingCart` class.
|
||||
|
||||
```js
|
||||
assert.isFunction(cart.calculateTaxes);
|
||||
```
|
||||
|
||||
Your `calculateTaxes` method should take an `amount` parameter.
|
||||
|
||||
```js
|
||||
assert.match(cart.calculateTaxes.toString(), /\(\s*amount\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,368 @@
|
||||
---
|
||||
id: 63f02bdeb9b428208b97eb6b
|
||||
title: Step 45
|
||||
challengeType: 0
|
||||
dashedName: step-45
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Your `calculateTaxes` method should return the value of the `taxRate` (divided by 100, to convert it to a percent) multiplied by the `amount` parameter.
|
||||
|
||||
For clarity, wrap the `taxRate / 100` calculation in parentheses.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should divide the `taxRate` by 100 in your `calculateTaxes` method. Remember to use the `this` keyword.
|
||||
|
||||
```js
|
||||
const afterCalculateTaxes = code.split('calculateTaxes')[1];
|
||||
assert.match(afterCalculateTaxes, /this\s*\.\s*taxRate\s*\/\s*100/);
|
||||
```
|
||||
|
||||
You should wrap the `this.taxRate / 100` calculation in parentheses.
|
||||
|
||||
```js
|
||||
const afterCalculateTaxes = code.split('calculateTaxes')[1];
|
||||
assert.match(afterCalculateTaxes, /\(\s*this\s*\.\s*taxRate\s*\/\s*100\s*\)/);
|
||||
```
|
||||
|
||||
You should multiply the `amount` parameter by the `taxRate` divided by 100 in your `calculateTaxes` method.
|
||||
|
||||
```js
|
||||
const afterCalculateTaxes = code.split('calculateTaxes')[1];
|
||||
assert.match(afterCalculateTaxes, /amount\s*\*\s*\(\s*this\s*\.\s*taxRate\s*\/\s*100\s*\)|\(\s*this\s*\.\s*taxRate\s*\/\s*100\s*\)\s*\*\s*amount/);
|
||||
```
|
||||
|
||||
Your `calculateTaxes` method should return the value of the `taxRate` (divided by 100, to convert it to a percent) multiplied by the `amount` parameter.
|
||||
|
||||
```js
|
||||
console.log(cart.calculateTaxes(10), (cart.taxRate / 100) * 10);
|
||||
assert.equal(cart.calculateTaxes(10), (cart.taxRate / 100) * 10);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
calculateTaxes(amount) {
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,361 @@
|
||||
---
|
||||
id: 63f02c6e18773921ba50aa53
|
||||
title: Step 46
|
||||
challengeType: 0
|
||||
dashedName: step-46
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Because of the way computers store and work with numbers, calculations involving decimal numbers can result in some strange behavior. For example, `0.1 + 0.2` is not equal to `0.3`. This is because computers store decimal numbers as binary fractions, and some binary fractions cannot be represented exactly as decimal fractions.
|
||||
|
||||
We want to clean up the number result from your calculation. Wrap your calculation in parentheses (don't include the `return` statement!) and call the `.toFixed()` method on it. Pass the `.toFixed()` method the number `2` as an argument. This will round the number to two decimal places and return a string.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should wrap your calculation in parentheses.
|
||||
|
||||
```js
|
||||
const afterCalculateTaxes = code.split('calculateTaxes')[1];
|
||||
assert.match(afterCalculateTaxes, /return\s*\(\s*\(\s*this\s*\.\s*taxRate\s*\/\s*100\s*\)\s*\*\s*amount\s*\)/)
|
||||
```
|
||||
|
||||
You should call the `.toFixed()` method on your calculation.
|
||||
|
||||
```js
|
||||
const afterCalculateTaxes = code.split('calculateTaxes')[1];
|
||||
assert.match(afterCalculateTaxes, /return\s*\(\s*\(\s*this\s*\.\s*taxRate\s*\/\s*100\s*\)\s*\*\s*amount\s*\)\s*\.\s*toFixed\(/)
|
||||
```
|
||||
|
||||
You should pass the `.toFixed()` method the number `2` as an argument.
|
||||
|
||||
```js
|
||||
const afterCalculateTaxes = code.split('calculateTaxes')[1];
|
||||
assert.match(afterCalculateTaxes, /return\s*\(\s*\(\s*this\s*\.\s*taxRate\s*\/\s*100\s*\)\s*\*\s*amount\s*\)\s*\.\s*toFixed\s*\(\s*2\s*\)/)
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
calculateTaxes(amount) {
|
||||
return (this.taxRate / 100) * amount;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,347 @@
|
||||
---
|
||||
id: 63f0311f5ea9382388d6124f
|
||||
title: Step 47
|
||||
challengeType: 0
|
||||
dashedName: step-47
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The issue with `.toFixed()` returning a string is that you want to be able to perform calculations with the tax rate. To fix this, you can pass the `.toFixed()` call (including the calculation) to the `parseFloat()` function. This will convert the fixed string back into a number, preserving the existing decimal places.
|
||||
|
||||
Pass your `.toFixed()` call to `parseFloat()`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should pass your entire calculation (excluding the `return` statement) to `parseFloat()`.
|
||||
|
||||
```js
|
||||
const afterCalculateTaxes = code.split('calculateTaxes')[1];
|
||||
assert.match(afterCalculateTaxes, /return\s*parseFloat\(\s*\(\s*\(\s*this\s*\.\s*taxRate\s*\/\s*100\s*\)\s*\*\s*amount\s*\)\s*\.\s*toFixed\s*\(\s*2\s*\)\s*\)/)
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
calculateTaxes(amount) {
|
||||
return ((this.taxRate / 100) * amount).toFixed(2);
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,339 @@
|
||||
---
|
||||
id: 63f033fdb1fbcc254999fcc3
|
||||
title: Step 37
|
||||
challengeType: 0
|
||||
dashedName: step-37
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Your cart currently isn't visible on the webpage. To make it visible, start by adding an event listener to the `cartBtn` variable, listening for the click event. The callback does not need any parameters.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add an event listener to the `cartBtn` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /cartBtn\s*\.\s*addEventListener\s*\(/);
|
||||
```
|
||||
|
||||
You should listen for a `click` event on the `cartBtn` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /cartBtn\s*\.\s*addEventListener\s*\(\s*('|"|`)click\1\s*/);
|
||||
```
|
||||
|
||||
You should add an empty callback function (using arrow syntax) to the event listener. Remember that it does not need any parameters.
|
||||
|
||||
```js
|
||||
assert.match(code, /cartBtn\s*\.\s*addEventListener\s*\(\s*('|"|`)click\1\s*,\s*\(\s*\)\s*=>\s*\{\s*\}\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,335 @@
|
||||
---
|
||||
id: 63f03446c2ed3e264be6c7fc
|
||||
title: Step 38
|
||||
challengeType: 0
|
||||
dashedName: step-38
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Start by inverting the value of `isCartShowing`. Remember that you can use the logical not operator `!` to invert the value of a boolean. Assign the inverted value to `isCartShowing`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should invert the value of `isCartShowing`.
|
||||
|
||||
```js
|
||||
assert.match(code, /!isCartShowing/);
|
||||
```
|
||||
|
||||
You should assign the inverted value of `isCartShowing` to `isCartShowing`.
|
||||
|
||||
```js
|
||||
assert.match(code, /isCartShowing\s*=\s*!isCartShowing/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
cartBtn.addEventListener("click", () => {
|
||||
|
||||
});
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,348 @@
|
||||
---
|
||||
id: 63f0348a54a177272071a595
|
||||
title: Step 39
|
||||
challengeType: 0
|
||||
dashedName: step-39
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now assign the `textContent` of the `showHideCartSpan` variable the result of a ternary expression which checks if `isCartShowing` is true. If it is, set the `textContent` to `Hide`, otherwise set it to `Show`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the assignment operator on the `textContent` property of the `showHideCartSpan` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /showHideCartSpan\s*\.\s*textContent\s*=\s*/)
|
||||
```
|
||||
|
||||
You should use ternary syntax to check if `isCartShowing` is true.
|
||||
|
||||
```js
|
||||
assert.match(code, /showHideCartSpan\s*\.\s*textContent\s*=\s*isCartShowing\s*\?\s*/)
|
||||
```
|
||||
|
||||
You should set the `textContent` of the `showHideCartSpan` variable to `Hide` if `isCartShowing` is true.
|
||||
|
||||
```js
|
||||
assert.match(code, /showHideCartSpan\s*\.\s*textContent\s*=\s*isCartShowing\s*\?\s*('|"|`)Hide\1\s*:\s*/)
|
||||
```
|
||||
|
||||
You should set the `textContent` of the `showHideCartSpan` variable to `Show` if `isCartShowing` is false.
|
||||
|
||||
```js
|
||||
assert.match(code, /showHideCartSpan\s*\.\s*textContent\s*=\s*isCartShowing\s*\?\s*('|"|`)Hide\1\s*:\s*('|"|`)Show\2/)
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
|
||||
});
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,357 @@
|
||||
---
|
||||
id: 63f034d012f74627ce538d3a
|
||||
title: Step 40
|
||||
challengeType: 0
|
||||
dashedName: step-40
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Finally, update the `display` property of the `style` object of the `cartContainer` variable to another ternary which checks if `isCartShowing` is true. If it is, set the `display` property to `block`, otherwise set it to `none`.
|
||||
|
||||
Now you should be able to see your cart and add items to it.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should access the `display` property of the `style` property of the `cartContainer` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /cartContainer\s*\.\s*style\s*\.\s*display/)
|
||||
```
|
||||
|
||||
You should use the assignment operator on the `display` property of the `style` property of the `cartContainer` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /cartContainer\s*\.\s*style\s*\.\s*display\s*=\s*/)
|
||||
```
|
||||
|
||||
You should use ternary syntax to check if `isCartShowing` is true.
|
||||
|
||||
```js
|
||||
assert.match(code, /cartContainer\s*\.\s*style\s*\.\s*display\s*=\s*isCartShowing\s*\?\s*/)
|
||||
```
|
||||
|
||||
You should set the `display` property of the `style` property of the `cartContainer` variable to `block` if `isCartShowing` is true.
|
||||
|
||||
```js
|
||||
assert.match(code, /cartContainer\s*\.\s*style\s*\.\s*display\s*=\s*isCartShowing\s*\?\s*('|"|`)block\1\s*:\s*/)
|
||||
```
|
||||
|
||||
You should set the `display` property of the `style` property of the `cartContainer` variable to `none` if `isCartShowing` is false.
|
||||
|
||||
```js
|
||||
assert.match(code, /cartContainer\s*\.\s*style\s*\.\s*display\s*=\s*isCartShowing\s*\?\s*('|"|`)block\1\s*:\s*('|"|`)none\2/)
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
|
||||
});
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,353 @@
|
||||
---
|
||||
id: 63f03686c5ea863533ec71f4
|
||||
title: Step 48
|
||||
challengeType: 0
|
||||
dashedName: step-48
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Declare a variable `tax` and assign it the value of calling your new `.calculateTaxes()` method, passing `subTotal` as the argument.
|
||||
|
||||
# --hints--
|
||||
|
||||
Use `const` to declare a variable named `tax`.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /const\s+tax\s*=/);
|
||||
```
|
||||
|
||||
Assign the value of calling your new `.calculateTaxes()` method, passing `subTotal` as the argument, to the `tax` variable.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /const\s*tax\s*=\s*this\s*\.\s*calculateTaxes\s*\(\s*subTotal\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,352 @@
|
||||
---
|
||||
id: 63f036ec91fdf238c90665f5
|
||||
title: Step 49
|
||||
challengeType: 0
|
||||
dashedName: step-49
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Update the `total` value to be the sum of the `subTotal` and `tax` values.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should update the `total` value. Remember to use the `this` keyword.
|
||||
|
||||
```js
|
||||
assert.match(cart.calculateTotal.toString(), /this\.total/);
|
||||
```
|
||||
|
||||
You should set the `total` value to be the sum of the `subTotal` and `tax` values.
|
||||
|
||||
```js
|
||||
assert.match(cart.calculateTotal.toString(), /this\.total\s*=\s*(subTotal\s*\+\s*tax|tax\s*\+\s*subTotal)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,367 @@
|
||||
---
|
||||
id: 63f0370b340915399d31e5eb
|
||||
title: Step 50
|
||||
challengeType: 0
|
||||
dashedName: step-50
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You're going to update the HTML in this method as well. Set the `textContent` of the `cartSubTotal` to be the value of `subTotal` to a fixed 2 decimal places. Use template literal syntax to add the dollar sign to the beginning of the value.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should access the `textContent` property of the `cartSubTotal` element.
|
||||
|
||||
```js
|
||||
assert.match(cart.calculateTotal.toString(), /cartSubTotal\.textContent/);
|
||||
```
|
||||
|
||||
You should call the `.toFixed()` method on the `subTotal` variable, passing `2` as the argument.
|
||||
|
||||
```js
|
||||
assert.match(cart.calculateTotal.toString(), /subTotal\.toFixed\(\s*2\s*\)/);
|
||||
```
|
||||
|
||||
You should use template literal syntax to add the dollar sign before your `.toFixed()` call.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /`\$\$\{subTotal\.toFixed\(\s*2\s*\)\}\`/);
|
||||
```
|
||||
|
||||
You should set the `textContent` of the `cartSubTotal` element to your template string.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /cartSubTotal\.textContent\s*=\s*`\$\$\{subTotal\.toFixed\(\s*2\s*\)\}\`/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,394 @@
|
||||
---
|
||||
id: 63f0374d5351223a747c301d
|
||||
title: Step 51
|
||||
challengeType: 0
|
||||
dashedName: step-51
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Following the same pattern as your `cartSubTotal`, update the `cartTaxes` to display the `tax` value, and your `cartTotal` to display the `total` property.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should access the `textContent` property of the `cartTaxes` element.
|
||||
|
||||
```js
|
||||
assert.match(cart.calculateTotal.toString(), /cartTaxes\.textContent/);
|
||||
```
|
||||
|
||||
You should call the `.toFixed()` method on the `tax` variable, passing `2` as the argument.
|
||||
|
||||
```js
|
||||
assert.match(cart.calculateTotal.toString(), /tax\.toFixed\(\s*2\s*\)/);
|
||||
```
|
||||
|
||||
You should use template literal syntax to add the dollar sign before your `.toFixed()` call.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /`\$\$\{tax\.toFixed\(\s*2\s*\)\}\`/);
|
||||
```
|
||||
|
||||
You should set the `textContent` of the `cartTaxes` element to `tax.toFixed` template string.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /cartTaxes\.textContent\s*=\s*`\$\$\{tax\.toFixed\(\s*2\s*\)\}\`/);
|
||||
```
|
||||
|
||||
You should access the `textContent` property of the `cartTotal` element.
|
||||
|
||||
```js
|
||||
assert.match(cart.calculateTotal.toString(), /cartTotal\.textContent/);
|
||||
```
|
||||
|
||||
You should call the `.toFixed()` method on the `total` variable, passing `2` as the argument. Remember to use the `this` keyword.
|
||||
|
||||
```js
|
||||
assert.match(cart.calculateTotal.toString(), /this\.total\.toFixed\(\s*2\s*\)/);
|
||||
```
|
||||
|
||||
You should use template literal syntax to add the dollar sign before your `.toFixed()` call.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /`\$\$\{this\.total\.toFixed\(\s*2\s*\)\}\`/);
|
||||
```
|
||||
|
||||
You should set the `textContent` of the `cartTotal` element to your `total.toFixed` template string.
|
||||
|
||||
```js
|
||||
const afterCalculateTotal = code.split('calculateTotal')[1];
|
||||
assert.match(afterCalculateTotal, /cartTotal\.textContent\s*=\s*`\$\$\{this\.total\.toFixed\(\s*2\s*\)\}\`/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,352 @@
|
||||
---
|
||||
id: 63f0378e173e3c3b7638b528
|
||||
title: Step 52
|
||||
challengeType: 0
|
||||
dashedName: step-52
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Finally, return the value of the `total` property. Remember your `this` keyword.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `calculateTotal` method should return the value of the `total` property.
|
||||
|
||||
```js
|
||||
assert.equal(cart.calculateTotal(), 0);
|
||||
cart.addItem(1, products);
|
||||
assert.approximately(cart.calculateTotal(), 14.06, 0.1);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
|
||||
cartTaxes.textContent = `$${tax.toFixed(2)}`;
|
||||
cartTotal.textContent = `$${this.total.toFixed(2)}`;
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,353 @@
|
||||
---
|
||||
id: 63f038a0ae041d3c5b0cdf23
|
||||
title: Step 54
|
||||
challengeType: 0
|
||||
dashedName: step-54
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Your last feature is to allow users to clear their cart. Add a `clearCart()` method to your `ShoppingCart` class.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `ShoppingCart` class should have a `clearCart` method.
|
||||
|
||||
```js
|
||||
assert.isFunction(cart.clearCart);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
|
||||
cartTaxes.textContent = `$${tax.toFixed(2)}`;
|
||||
cartTotal.textContent = `$${this.total.toFixed(2)}`;
|
||||
return this.total;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
cart.calculateTotal();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,371 @@
|
||||
---
|
||||
id: 63f038e671d3f73d5a041973
|
||||
title: Step 55
|
||||
challengeType: 0
|
||||
dashedName: step-55
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The first thing you should do is check if the `items` array is empty. If it is, display an `alert` to the user with the text `Your shopping cart is already empty`, then return from the function.
|
||||
|
||||
Remember that `0` is a falsy value, so you can use the `!` operator to check if the array is empty.
|
||||
|
||||
After displaying the alert, return from the function to stop execution.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create an `if` statement that checks if the `items` array is empty, using the negation operator.
|
||||
|
||||
```js
|
||||
assert.match(cart.clearCart.toString(), /if\s*\(\s*!\s*this\s*\.\s*items\s*\.\s*length\s*\)/);
|
||||
```
|
||||
|
||||
Your `if` statement should display an `alert` to the user with the text `Your shopping cart is already empty`.
|
||||
|
||||
```js
|
||||
assert.match(cart.clearCart.toString(), /if\s*\(\s*!\s*this\s*\.\s*items\s*\.\s*length\s*\)\s*\{\s*alert\s*\(\s*('|"|`)Your shopping cart is already empty\1\s*\)\s*/);
|
||||
```
|
||||
|
||||
Your `if` statement should return from the function.
|
||||
|
||||
```js
|
||||
assert.match(cart.clearCart.toString(), /if\s*\(\s*!\s*this\s*\.\s*items\s*\.\s*length\s*\)\s*\{\s*alert\s*\(\s*('|"|`)Your shopping cart is already empty\1\s*\)\s*;?\s*return\s*;?\s*\}/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
clearCart() {
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
|
||||
cartTaxes.textContent = `$${tax.toFixed(2)}`;
|
||||
cartTotal.textContent = `$${this.total.toFixed(2)}`;
|
||||
return this.total;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
cart.calculateTotal();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,381 @@
|
||||
---
|
||||
id: 63f039dbcef7673e4e758fa3
|
||||
title: Step 56
|
||||
challengeType: 0
|
||||
dashedName: step-56
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Browsers have a built-in `confirm()` function which displays a confirmation prompt to the user. `confirm()` accepts a string, which is the message displayed to the user. It returns `true` if the user confirms, and `false` if the user cancels.
|
||||
|
||||
Declare a variable `isCartCleared` and assign it the value of calling `confirm()` with the string `"Are you sure you want to clear all items from your shopping cart?"`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `const` to declare the `isCartCleared` variable.
|
||||
|
||||
```js
|
||||
const afterClearCart = code.split('clearCart()')[1];
|
||||
assert.match(afterClearCart, /const\s+isCartCleared\s*=/);
|
||||
```
|
||||
|
||||
You should call the `confirm()` function.
|
||||
|
||||
```js
|
||||
assert.match(cart.clearCart.toString(), /confirm\s*\(/);
|
||||
```
|
||||
|
||||
You should pass the string `Are you sure you want to clear all items from your shopping cart?` to the `confirm()` function.
|
||||
|
||||
```js
|
||||
assert.match(cart.clearCart.toString(), /confirm\s*\(\s*('|"|`)Are you sure you want to clear all items from your shopping cart\?\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the value of the `confirm()` function to the `isCartCleared` variable.
|
||||
|
||||
```js
|
||||
assert.match(cart.clearCart.toString(), /isCartCleared\s*=\s*confirm\s*\(\s*('|"|`)Are you sure you want to clear all items from your shopping cart\?\1\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
clearCart() {
|
||||
if (!this.items.length) {
|
||||
alert("Your shopping cart is already empty");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
|
||||
cartTaxes.textContent = `$${tax.toFixed(2)}`;
|
||||
cartTotal.textContent = `$${this.total.toFixed(2)}`;
|
||||
return this.total;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
cart.calculateTotal();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,378 @@
|
||||
---
|
||||
id: 63f03a7143a6ef3f7f3344f0
|
||||
title: Step 57
|
||||
challengeType: 0
|
||||
dashedName: step-57
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You only want to clear the cart if the user confirms the prompt. Create an `if` statement that checks if the user confirmed the prompt.
|
||||
|
||||
In the `if` statement, set the `items` property back to an empty array, then set the `total` property to `0`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create an `if` statement that checks if the user confirmed the prompt. Remember that you can check the truthiness of `isCartCleared` directly.
|
||||
|
||||
```js
|
||||
assert.match(cart.clearCart.toString(), /if\s*\(\s*isCartCleared\s*\)/);
|
||||
```
|
||||
|
||||
Your `if` statement should set the `items` property back to an empty array.
|
||||
|
||||
```js
|
||||
assert.match(cart.clearCart.toString(), /if\s*\(\s*isCartCleared\s*\)\s*{\s*this\s*\.\s*items\s*=\s*\[\s*\]/);
|
||||
```
|
||||
|
||||
Your `if` statement should set the `total` property to `0`.
|
||||
|
||||
```js
|
||||
assert.match(cart.clearCart.toString(), /if\s*\(\s*isCartCleared\s*\)\s*{\s*this\s*\.\s*items\s*=\s*\[\s*\]\s*;?\s*this\s*\.\s*total\s*=\s*0\s*;?\s*}/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
clearCart() {
|
||||
if (!this.items.length) {
|
||||
alert("Your shopping cart is already empty");
|
||||
return;
|
||||
}
|
||||
|
||||
const isCartCleared = confirm(
|
||||
"Are you sure you want to clear all items from your shopping cart?"
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
|
||||
cartTaxes.textContent = `$${tax.toFixed(2)}`;
|
||||
cartTotal.textContent = `$${this.total.toFixed(2)}`;
|
||||
return this.total;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
cart.calculateTotal();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,368 @@
|
||||
---
|
||||
id: 63f03ac2b428b2404a5a7518
|
||||
title: Step 58
|
||||
challengeType: 0
|
||||
dashedName: step-58
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You also need to start clearing the HTML. Set the `innerHTML` property of the `productsContainer` back to an empty string.
|
||||
|
||||
# --hints--
|
||||
|
||||
In your `if` statement, you should set the `innerHTML` property of the `productsContainer` back to an empty string.
|
||||
|
||||
```js
|
||||
assert.match(cart.clearCart.toString(), /if\s*\(\s*isCartCleared\s*\)\s*{\s*this\s*\.\s*items\s*=\s*\[\s*\]\s*;?\s*this\s*\.\s*total\s*=\s*0\s*;?\s*productsContainer\.innerHTML\s*=\s*('|"|`)\1\s*;?\s*}/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
clearCart() {
|
||||
if (!this.items.length) {
|
||||
alert("Your shopping cart is already empty");
|
||||
return;
|
||||
}
|
||||
|
||||
const isCartCleared = confirm(
|
||||
"Are you sure you want to clear all items from your shopping cart?"
|
||||
);
|
||||
|
||||
if (isCartCleared) {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
|
||||
}
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
|
||||
cartTaxes.textContent = `$${tax.toFixed(2)}`;
|
||||
cartTotal.textContent = `$${this.total.toFixed(2)}`;
|
||||
return this.total;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
cart.calculateTotal();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,395 @@
|
||||
---
|
||||
id: 63f03af535682e4138fdb915
|
||||
title: Step 59
|
||||
challengeType: 0
|
||||
dashedName: step-59
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Set the `textContent` of the `totalNumberOfItems`, `cartSubTotal`, `cartTaxes`, and `cartTotal` elements all to the number `0`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should set the `textContent` of the `totalNumberOfItems` element to `0`.
|
||||
|
||||
```js
|
||||
const secondIf = cart.clearCart.toString().split('if')[2];
|
||||
const inIf = secondIf.split('}')[0];
|
||||
assert.match(inIf, /totalNumberOfItems\.textContent\s*=\s*0/);
|
||||
```
|
||||
|
||||
You should set the `textContent` of the `cartSubTotal` element to `0`.
|
||||
|
||||
```js
|
||||
const secondIf = cart.clearCart.toString().split('if')[2];
|
||||
const inIf = secondIf.split('}')[0];
|
||||
assert.match(inIf, /cartSubTotal\.textContent\s*=\s*0/);
|
||||
```
|
||||
|
||||
You should set the `textContent` of the `cartTaxes` element to `0`.
|
||||
|
||||
```js
|
||||
const secondIf = cart.clearCart.toString().split('if')[2];
|
||||
const inIf = secondIf.split('}')[0];
|
||||
assert.match(inIf, /cartTaxes\.textContent\s*=\s*0/);
|
||||
```
|
||||
|
||||
You should set the `textContent` of the `cartTotal` element to `0`.
|
||||
|
||||
```js
|
||||
const secondIf = cart.clearCart.toString().split('if')[2];
|
||||
const inIf = secondIf.split('}')[0];
|
||||
assert.match(inIf, /cartTotal\.textContent\s*=\s*0/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
clearCart() {
|
||||
if (!this.items.length) {
|
||||
alert("Your shopping cart is already empty");
|
||||
return;
|
||||
}
|
||||
|
||||
const isCartCleared = confirm(
|
||||
"Are you sure you want to clear all items from your shopping cart?"
|
||||
);
|
||||
|
||||
if (isCartCleared) {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
productsContainer.innerHTML = "";
|
||||
|
||||
}
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
|
||||
cartTaxes.textContent = `$${tax.toFixed(2)}`;
|
||||
cartTotal.textContent = `$${this.total.toFixed(2)}`;
|
||||
return this.total;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
cart.calculateTotal();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,744 @@
|
||||
---
|
||||
id: 63f03b1ed5ab15420c057463
|
||||
title: Step 60
|
||||
challengeType: 0
|
||||
dashedName: step-60
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Your final step is to make your clear button functional. Add a `click` event listener to the `clearCartBtn`. For the callback, you can pass in `cart.clearCart` directly.
|
||||
|
||||
However, doing so will not work, because the context of `this` will be the `clearCartBtn` element. You need to bind the `clearCart` method to the `cart` object.
|
||||
|
||||
You can do this by passing `cart.clearCart.bind(cart)` as the callback.
|
||||
|
||||
And with that, your shopping cart project is complete!
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add an event listener to your `clearCartBtn` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /clearCartBtn\.addEventListener\(/);
|
||||
```
|
||||
|
||||
Your event listener should listen for the `click` event.
|
||||
|
||||
```js
|
||||
assert.match(code, /clearCartBtn\.addEventListener\(\s*('|"|`)click\1\s*,/);
|
||||
```
|
||||
|
||||
Your event listener should take `cart.clearCart.bind(cart)` as the callback.
|
||||
|
||||
```js
|
||||
assert.match(code, /clearCartBtn\.addEventListener\(\s*('|"|`)click\1\s*,\s*cart\.clearCart\s*.bind\(\s*cart\s*\)\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
clearCart() {
|
||||
if (!this.items.length) {
|
||||
alert("Your shopping cart is already empty");
|
||||
return;
|
||||
}
|
||||
|
||||
const isCartCleared = confirm(
|
||||
"Are you sure you want to clear all items from your shopping cart?"
|
||||
);
|
||||
|
||||
if (isCartCleared) {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
productsContainer.innerHTML = "";
|
||||
totalNumberOfItems.textContent = 0;
|
||||
cartSubTotal.textContent = 0;
|
||||
cartTaxes.textContent = 0;
|
||||
cartTotal.textContent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
|
||||
cartTaxes.textContent = `$${tax.toFixed(2)}`;
|
||||
cartTotal.textContent = `$${this.total.toFixed(2)}`;
|
||||
return this.total;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
cart.calculateTotal();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
clearCart() {
|
||||
if (!this.items.length) {
|
||||
alert("Your shopping cart is already empty");
|
||||
return;
|
||||
}
|
||||
|
||||
const isCartCleared = confirm(
|
||||
"Are you sure you want to clear all items from your shopping cart?"
|
||||
);
|
||||
|
||||
if (isCartCleared) {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
productsContainer.innerHTML = "";
|
||||
totalNumberOfItems.textContent = 0;
|
||||
cartSubTotal.textContent = 0;
|
||||
cartTaxes.textContent = 0;
|
||||
cartTotal.textContent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
|
||||
cartTaxes.textContent = `$${tax.toFixed(2)}`;
|
||||
cartTotal.textContent = `$${this.total.toFixed(2)}`;
|
||||
return this.total;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
cart.calculateTotal();
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
|
||||
clearCartBtn.addEventListener("click", cart.clearCart.bind(cart));
|
||||
```
|
||||
@@ -0,0 +1,352 @@
|
||||
---
|
||||
id: 63f6721d5110af243ef8f3d9
|
||||
title: Step 53
|
||||
challengeType: 0
|
||||
dashedName: step-53
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now call your `.calculateTotal()` method inside your `forEach` loop.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call `cart.calculateTotal()` inside your `forEach` loop.
|
||||
|
||||
```js
|
||||
const afterForEach = code.split('[...addToCartBtns].forEach(')[1];
|
||||
assert.match(afterForEach, /cart\.calculateTotal\(\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCounts() {
|
||||
return this.items.length;
|
||||
}
|
||||
|
||||
calculateTaxes(amount) {
|
||||
return parseFloat(((this.taxRate / 100) * amount).toFixed(2));
|
||||
}
|
||||
|
||||
calculateTotal() {
|
||||
const subTotal = this.items.reduce((total, item) => total + item.price, 0);
|
||||
const tax = this.calculateTaxes(subTotal);
|
||||
this.total = subTotal + tax;
|
||||
cartSubTotal.textContent = `$${subTotal.toFixed(2)}`;
|
||||
cartTaxes.textContent = `$${tax.toFixed(2)}`;
|
||||
cartTotal.textContent = `$${this.total.toFixed(2)}`;
|
||||
return this.total;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
--fcc-editable-region--
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
cart.addItem(Number(event.target.id), products);
|
||||
totalNumberOfItems.textContent = cart.getCounts();
|
||||
|
||||
})
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
|
||||
cartBtn.addEventListener("click", () => {
|
||||
isCartShowing = !isCartShowing;
|
||||
showHideCartSpan.textContent = isCartShowing ? "Hide" : "Show";
|
||||
cartContainer.style.display = isCartShowing ? "block" : "none";
|
||||
});
|
||||
```
|
||||
@@ -9,7 +9,7 @@ dashedName: step-36
|
||||
|
||||
這正是你想要的,但如果口味和價格在同一條線上,那就太好了。 `p` 元素是 <dfn>塊級</dfn> 元素,因此它們佔據了其父元素的整個寬度。
|
||||
|
||||
要將它們放在同一行,你需要對 `p` 元素應用一些樣式,因此它們更像<dfn>內聯</dfn>元素。 將值爲 `item` 的 `class` 屬性添加到 `Coffee` 標題下的第一個 `article` 元素。
|
||||
To get them on the same line, you need to apply some styling to the `p` elements so they behave more like <dfn>inline</dfn> elements. To do that, start by adding a `class` attribute with the value `item` to the first `article` element under the `Coffee` heading.
|
||||
|
||||
# --hints--
|
||||
|
||||
|
||||
@@ -19,12 +19,6 @@ dashedName: step-24
|
||||
assert(document.querySelectorAll('table')?.[1]?.querySelector('tbody')?.querySelectorAll('tr')?.[3]?.querySelector('th'));
|
||||
```
|
||||
|
||||
Your text `Total Liabilities` should not include period `.`.
|
||||
|
||||
```js
|
||||
assert(document.querySelectorAll('table')?.[1]?.querySelector('tbody')?.querySelectorAll('tr')?.[3]?.querySelector('th')?.innerText !== 'Total Liabilities.');
|
||||
```
|
||||
|
||||
Your `th` element should have the text `Total Liabilities`.
|
||||
|
||||
```js
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
---
|
||||
id: 63ec14d1c216aa063f0be4af
|
||||
title: Step 1
|
||||
challengeType: 0
|
||||
dashedName: step-1
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You will be building a shopping cart application. The HTML and CSS are already provided, but you will need to build the JavaScript to make the page interactive.
|
||||
|
||||
To start, you will need to get some of your elements from the DOM. Start by using `document.getElementById()` to get the`#cart-container`, `#products-container`, and `#dessert-card-container` elements. Store them in variables named `cartContainer`, `productsContainer`, and `dessertCards`, respectively.
|
||||
|
||||
Since these will not change, remember to use `const` to declare them.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `document.getElementById()` to get the `#cart-container` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)cart-container\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#cart-container` element to a variable named `cartContainer`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cartContainer\s*=\s*document\.getElementById\(\s*('|"|`)cart-container\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#products-container` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)products-container\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#products-container` element to a variable named `productsContainer`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+productsContainer\s*=\s*document\.getElementById\(\s*('|"|`)products-container\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#dessert-card-container` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)dessert-card-container\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#dessert-card-container` element to a variable named `dessertCards`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+dessertCards\s*=\s*document\.getElementById\(\s*('|"|`)dessert-card-container\1\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,201 @@
|
||||
---
|
||||
id: 63ec19978a066607e23439f8
|
||||
title: Step 2
|
||||
challengeType: 0
|
||||
dashedName: step-2
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you need to get your two buttons. Continuing the pattern, get the `#cart-btn` and `#clear-cart-btn` elements. Store them in variables named `cartBtn` and `clearCartBtn`, respectively.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `document.getElementById()` to get the `#cart-btn` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)cart-btn\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#cart-btn` element to a variable named `cartBtn`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cartBtn\s*=\s*document\.getElementById\(\s*('|"|`)cart-btn\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#clear-cart-btn` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)clear-cart-btn\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#clear-cart-btn` element to a variable named `clearCartBtn`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+clearCartBtn\s*=\s*document\.getElementById\(\s*('|"|`)clear-cart-btn\1\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,227 @@
|
||||
---
|
||||
id: 63ec1a16f930b108b8a76806
|
||||
title: Step 3
|
||||
challengeType: 0
|
||||
dashedName: step-3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Next is to get your totals. Get the `#total-items`, `#subtotal`, `#taxes`, and `#total` elements. Store them in variables named `totalNumberOfItems`, `cartSubTotal`, `cartTaxes`, and `cartTotal`, respectively.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `document.getElementById()` to get the `#total-items` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)total-items\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#total-items` element to a variable named `totalNumberOfItems`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+totalNumberOfItems\s*=\s*document\.getElementById\(\s*('|"|`)total-items\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#subtotal` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)subtotal\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#subtotal` element to a variable named `cartSubTotal`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cartSubTotal\s*=\s*document\.getElementById\(\s*('|"|`)subtotal\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#taxes` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)taxes\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#taxes` element to a variable named `cartTaxes`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cartTaxes\s*=\s*document\.getElementById\(\s*('|"|`)taxes\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the `#total` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)total\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#total` element to a variable named `cartTotal`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cartTotal\s*=\s*document\.getElementById\(\s*('|"|`)total\1\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,209 @@
|
||||
---
|
||||
id: 63ec1bbf5584390a7d08d41f
|
||||
title: Step 4
|
||||
challengeType: 0
|
||||
dashedName: step-4
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The last element to get is the `#show-hide-cart` element. Store it in a variable named `showHideCartSpan`.
|
||||
|
||||
Then, use `let` to declare a variable named `isCartShowing` and set it to `false`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `document.getElementById()` to get the `#show-hide-cart` element.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\.getElementById\(\s*('|"|`)show-hide-cart\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the `#show-hide-cart` element to a variable named `showHideCartSpan`. Remember to use `const` to declare the variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+showHideCartSpan\s*=\s*document\.getElementById\(\s*('|"|`)show-hide-cart\1\s*\)/);
|
||||
```
|
||||
|
||||
You should use `let` to declare a variable named `isCartShowing`.
|
||||
|
||||
```js
|
||||
assert.match(code, /let\s+isCartShowing/);
|
||||
```
|
||||
|
||||
You should set the `isCartShowing` variable to `false`.
|
||||
|
||||
```js
|
||||
assert.match(code, /let\s+isCartShowing\s*=\s*false/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,198 @@
|
||||
---
|
||||
id: 63ec1cb59f2a4c0be5b6dfa0
|
||||
title: Step 5
|
||||
challengeType: 0
|
||||
dashedName: step-5
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
A shopping cart does not serve much purpose without products. Declare a `products` variable and set it to an empty array. Using an array will allow you to store multiple products.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `products` variable with `const`.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+products/);
|
||||
```
|
||||
|
||||
You should set the `products` variable to an empty array.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+products\s*=\s*\[\s*\]/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,226 @@
|
||||
---
|
||||
id: 63ec20a06fff670d37befbd9
|
||||
title: Step 6
|
||||
challengeType: 0
|
||||
dashedName: step-6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You now need to start adding products. Before you do that, you need to consider the structure of your product data. A product will need a unique identifier to distinguish it from other products, a price so people know how much it costs, and a name so people know what they are buying. You should also add a category to each product.
|
||||
|
||||
Add an object to your `products` array. Give this object an `id` property set to the number `1`, a `name` property set to `Vanilla Cupcakes (6 Pack)`, a `price` property set to the number `12.99`, and a `category` property set to `Cupcake`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your products array should have one value.
|
||||
|
||||
```js
|
||||
assert.equal(products.length, 1);
|
||||
```
|
||||
|
||||
Your products array should have an object as its first value.
|
||||
|
||||
```js
|
||||
assert.isObject(products[0]);
|
||||
```
|
||||
|
||||
Your products array should have an object with an `id` property set to the number `1`.
|
||||
|
||||
```js
|
||||
assert.equal(products[0].id, 1);
|
||||
```
|
||||
|
||||
Your products array should have an object with a `name` property set to `Vanilla Cupcakes (6 Pack)`.
|
||||
|
||||
```js
|
||||
assert.equal(products[0].name, 'Vanilla Cupcakes (6 Pack)');
|
||||
```
|
||||
|
||||
Your products array should have an object with a `price` property set to the number `12.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[0].price, 12.99);
|
||||
```
|
||||
|
||||
Your products array should have an object with a `category` property set to `Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[0].category, 'Cupcake');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
--fcc-editable-region--
|
||||
const products = [
|
||||
|
||||
];
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,472 @@
|
||||
---
|
||||
id: 63ec3287b182ec0efe8a3135
|
||||
title: Step 7
|
||||
challengeType: 0
|
||||
dashedName: step-7
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Following that same data structure, add the products from this table (in order) to your `products` array. Increment the `id` for each product, counting up.
|
||||
|
||||
| `name` | `price` | `category` |
|
||||
| ------------------------------ | ------- | ----------- |
|
||||
| `French Macaroon` | `3.99` | `Macaroon` |
|
||||
| `Pumpkin Cupcake` | `3.99` | `Cupcake` |
|
||||
| `Chocolate Cupcake` | `5.99` | `Cupcake` |
|
||||
| `Chocolate Pretzels (4 Pack)` | `10.99` | `Pretzel` |
|
||||
| `Strawberry Ice Cream` | `2.99` | `Ice Cream` |
|
||||
| `Chocolate Macaroons (4 Pack)` | `9.99` | `Macaroon` |
|
||||
| `Strawberry Pretzel` | `4.99` | `Pretzel` |
|
||||
| `Butter Pecan Ice Cream` | `2.99` | `Ice Cream` |
|
||||
| `Rocky Road Ice Cream` | `2.99` | `Ice Cream` |
|
||||
| `Vanilla Macaroons (5 Pack)` | `11.99` | `Macaroon` |
|
||||
| `Lemon Cupcakes (4 Pack)` | `12.99` | `Cupcake` |
|
||||
|
||||
# --hints--
|
||||
|
||||
Your second object in the `products` array should have an `id` property set to the number `2`.
|
||||
|
||||
```js
|
||||
assert.equal(products[1].id, 2);
|
||||
```
|
||||
|
||||
Your second object in the `products` array should have a `name` property set to `French Macaroon`.
|
||||
|
||||
```js
|
||||
assert.equal(products[1].name, 'French Macaroon');
|
||||
```
|
||||
|
||||
Your second object in the `products` array should have a `price` property set to the number `3.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[1].price, 3.99);
|
||||
```
|
||||
|
||||
Your second object in the `products` array should have a `category` property set to `Macaroon`.
|
||||
|
||||
```js
|
||||
assert.equal(products[1].category, 'Macaroon');
|
||||
```
|
||||
|
||||
Your third object in the `products` array should have an `id` property set to the number `3`.
|
||||
|
||||
```js
|
||||
assert.equal(products[2].id, 3);
|
||||
```
|
||||
|
||||
Your third object in the `products` array should have a `name` property set to `Pumpkin Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[2].name, 'Pumpkin Cupcake');
|
||||
```
|
||||
|
||||
Your third object in the `products` array should have a `price` property set to the number `3.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[2].price, 3.99);
|
||||
```
|
||||
|
||||
Your third object in the `products` array should have a `category` property set to `Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[2].category, 'Cupcake');
|
||||
```
|
||||
|
||||
Your fourth object in the `products` array should have an `id` property set to the number `4`.
|
||||
|
||||
```js
|
||||
assert.equal(products[3].id, 4);
|
||||
```
|
||||
|
||||
Your fourth object in the `products` array should have a `name` property set to `Chocolate Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[3].name, 'Chocolate Cupcake');
|
||||
```
|
||||
|
||||
Your fourth object in the `products` array should have a `price` property set to the number `5.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[3].price, 5.99);
|
||||
```
|
||||
|
||||
Your fourth object in the `products` array should have a `category` property set to `Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[3].category, 'Cupcake');
|
||||
```
|
||||
|
||||
Your fifth object in the `products` array should have an `id` property set to the number `5`.
|
||||
|
||||
```js
|
||||
assert.equal(products[4].id, 5);
|
||||
```
|
||||
|
||||
Your fifth object in the `products` array should have a `name` property set to `Chocolate Pretzels (4 Pack)`.
|
||||
|
||||
```js
|
||||
assert.equal(products[4].name, 'Chocolate Pretzels (4 Pack)');
|
||||
```
|
||||
|
||||
Your fifth object in the `products` array should have a `price` property set to the number `10.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[4].price, 10.99);
|
||||
```
|
||||
|
||||
Your fifth object in the `products` array should have a `category` property set to `Pretzel`.
|
||||
|
||||
```js
|
||||
assert.equal(products[4].category, 'Pretzel');
|
||||
```
|
||||
|
||||
Your sixth object in the `products` array should have an `id` property set to the number `6`.
|
||||
|
||||
```js
|
||||
assert.equal(products[5].id, 6);
|
||||
```
|
||||
|
||||
Your sixth object in the `products` array should have a `name` property set to `Strawberry Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[5].name, 'Strawberry Ice Cream');
|
||||
```
|
||||
|
||||
Your sixth object in the `products` array should have a `price` property set to the number `2.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[5].price, 2.99);
|
||||
```
|
||||
|
||||
Your sixth object in the `products` array should have a `category` property set to `Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[5].category, 'Ice Cream');
|
||||
```
|
||||
|
||||
Your seventh object in the `products` array should have an `id` property set to the number `7`.
|
||||
|
||||
```js
|
||||
assert.equal(products[6].id, 7);
|
||||
```
|
||||
|
||||
Your seventh object in the `products` array should have a `name` property set to `Chocolate Macaroons (4 Pack)`.
|
||||
|
||||
```js
|
||||
assert.equal(products[6].name, 'Chocolate Macaroons (4 Pack)');
|
||||
```
|
||||
|
||||
Your seventh object in the `products` array should have a `price` property set to the number `9.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[6].price, 9.99);
|
||||
```
|
||||
|
||||
Your seventh object in the `products` array should have a `category` property set to `Macaroon`.
|
||||
|
||||
```js
|
||||
assert.equal(products[6].category, 'Macaroon');
|
||||
```
|
||||
|
||||
Your eighth object in the `products` array should have an `id` property set to the number `8`.
|
||||
|
||||
```js
|
||||
assert.equal(products[7].id, 8);
|
||||
```
|
||||
|
||||
Your eighth object in the `products` array should have a `name` property set to `Strawberry Pretzel`.
|
||||
|
||||
```js
|
||||
assert.equal(products[7].name, 'Strawberry Pretzel');
|
||||
```
|
||||
|
||||
Your eighth object in the `products` array should have a `price` property set to the number `4.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[7].price, 4.99);
|
||||
```
|
||||
|
||||
Your eighth object in the `products` array should have a `category` property set to `Pretzel`.
|
||||
|
||||
```js
|
||||
assert.equal(products[7].category, 'Pretzel');
|
||||
```
|
||||
|
||||
Your ninth object in the `products` array should have an `id` property set to the number `9`.
|
||||
|
||||
```js
|
||||
assert.equal(products[8].id, 9);
|
||||
```
|
||||
|
||||
Your ninth object in the `products` array should have a `name` property set to `Butter Pecan Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[8].name, 'Butter Pecan Ice Cream');
|
||||
```
|
||||
|
||||
Your ninth object in the `products` array should have a `price` property set to the number `2.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[8].price, 2.99);
|
||||
```
|
||||
|
||||
Your ninth object in the `products` array should have a `category` property set to `Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[8].category, 'Ice Cream');
|
||||
```
|
||||
|
||||
Your tenth object in the `products` array should have an `id` property set to the number `10`.
|
||||
|
||||
```js
|
||||
assert.equal(products[9].id, 10);
|
||||
```
|
||||
|
||||
Your tenth object in the `products` array should have a `name` property set to `Rocky Road Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[9].name, 'Rocky Road Ice Cream');
|
||||
```
|
||||
|
||||
Your tenth object in the `products` array should have a `price` property set to the number `2.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[9].price, 2.99);
|
||||
```
|
||||
|
||||
Your tenth object in the `products` array should have a `category` property set to `Ice Cream`.
|
||||
|
||||
```js
|
||||
assert.equal(products[9].category, 'Ice Cream');
|
||||
```
|
||||
|
||||
Your eleventh object in the `products` array should have an `id` property set to the number `11`.
|
||||
|
||||
```js
|
||||
assert.equal(products[10].id, 11);
|
||||
```
|
||||
|
||||
Your eleventh object in the `products` array should have a `name` property set to `Vanilla Macaroons (5 Pack)`.
|
||||
|
||||
```js
|
||||
assert.equal(products[10].name, 'Vanilla Macaroons (5 Pack)');
|
||||
```
|
||||
|
||||
Your eleventh object in the `products` array should have a `price` property set to the number `11.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[10].price, 11.99);
|
||||
```
|
||||
|
||||
Your eleventh object in the `products` array should have a `category` property set to `Macaroon`.
|
||||
|
||||
```js
|
||||
assert.equal(products[10].category, 'Macaroon');
|
||||
```
|
||||
|
||||
Your twelfth object in the `products` array should have an `id` property set to the number `12`.
|
||||
|
||||
```js
|
||||
assert.equal(products[11].id, 12);
|
||||
```
|
||||
|
||||
Your twelfth object in the `products` array should have a `name` property set to `Lemon Cupcakes (4 Pack)`.
|
||||
|
||||
```js
|
||||
assert.equal(products[11].name, 'Lemon Cupcakes (4 Pack)');
|
||||
```
|
||||
|
||||
Your twelfth object in the `products` array should have a `price` property set to the number `12.99`.
|
||||
|
||||
```js
|
||||
assert.equal(products[11].price, 12.99);
|
||||
```
|
||||
|
||||
Your twelfth object in the `products` array should have a `category` property set to `Cupcake`.
|
||||
|
||||
```js
|
||||
assert.equal(products[11].category, 'Cupcake');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
--fcc-editable-region--
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
|
||||
];
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,281 @@
|
||||
---
|
||||
id: 63ec3427fc3e9214c9ed2a14
|
||||
title: Step 8
|
||||
challengeType: 0
|
||||
dashedName: step-8
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that you have your list of products, you can use JavaScript to insert them into the HTML. With this approach, if you decide to add more products, the HTML will automatically reflect that.
|
||||
|
||||
Start by calling the `.forEach` method of your `products` array. Use arrow syntax to create an empty callback function.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call the `.forEach` method of your `products` array.
|
||||
|
||||
```js
|
||||
assert.match(code, /products\.forEach\(/);
|
||||
```
|
||||
|
||||
You should use arrow syntax to create an empty callback function.
|
||||
|
||||
```js
|
||||
assert.match(code, /\(\s*\)\s*=>\s*\{\s*\}/)
|
||||
```
|
||||
|
||||
You should pass your empty callback function to the `.forEach` method.
|
||||
|
||||
```js
|
||||
assert.match(code, /products\.forEach\(\s*\(\s*\)\s*=>\s*\{\s*\}\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,277 @@
|
||||
---
|
||||
id: 63ec36f6133df7160be3ec66
|
||||
title: Step 9
|
||||
challengeType: 0
|
||||
dashedName: step-9
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Remember that you can use destructuring to extract multiple values from an array or object in a single statement.
|
||||
|
||||
For the first parameter of your callback function, destructure the `name`, `id`, `price`, and `category` properties from the object passed in.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use destructuring to declare `name`, `id`, `price`, and `category` parameters. For this test, order matters.
|
||||
|
||||
```js
|
||||
assert.match(code, /\{\s*name\s*,\s*id\s*,\s*price\s*,\s*category\s*\}/);
|
||||
```
|
||||
|
||||
Your destructuring should be the first parameter of the callback function.
|
||||
|
||||
```js
|
||||
assert.match(code, /products.forEach\(\s*\(\s*\{\s*name\s*,\s*id\s*,\s*price\s*,\s*category\s*\}\s*\)\s*=>/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
products.forEach(
|
||||
() => {}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,283 @@
|
||||
---
|
||||
id: 63ec47b454495519739486a7
|
||||
title: Step 10
|
||||
challengeType: 0
|
||||
dashedName: step-10
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need to display the available products in your HTML. Start by using the addition assignment operator to add an empty template literal string to the `innerHTML` property of the `dessertCards` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use access the `innerHTML` property of the `dessertCards` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /dessertCards\.innerHTML/);
|
||||
```
|
||||
|
||||
You should use the addition assignment operator on the `innerHTML` property.
|
||||
|
||||
```js
|
||||
assert.match(code, /dessertCards\.innerHTML\s*\+=\s*/);
|
||||
```
|
||||
|
||||
You should add an empty template literal string to the `innerHTML` property.
|
||||
|
||||
```js
|
||||
assert.match(code, /dessertCards\.innerHTML\s*\+=\s*`\s*`/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,297 @@
|
||||
---
|
||||
id: 63ee5d38a5d29d0696f8d820
|
||||
title: Step 11
|
||||
challengeType: 0
|
||||
dashedName: step-11
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In your template literal, create a `div` element with a class of `dessert-card`. In that `div`, create an `h2` element and give it the text of the `name` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `div` element.
|
||||
|
||||
```js
|
||||
assert.isAtLeast(document.querySelectorAll('div')?.length, 12);
|
||||
```
|
||||
|
||||
Your `div` element should have a class of `dessert-card`.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelectorAll('.dessert-card')?.length, 12);
|
||||
```
|
||||
|
||||
You should create an `h2` element.
|
||||
|
||||
```js
|
||||
assert.isAtLeast(document.querySelectorAll('h2')?.length, 12);
|
||||
```
|
||||
|
||||
Your `h2` element should have the text of the `name` variable.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelectorAll('h2')[0]?.textContent, 'Vanilla Cupcakes (6 Pack)');
|
||||
```
|
||||
|
||||
Your `h2` element should be inside the `div` element.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelectorAll('div h2')?.length, 12);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
|
||||
`;
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,309 @@
|
||||
---
|
||||
id: 63ee5d8f9e7168076e932fe2
|
||||
title: Step 12
|
||||
challengeType: 0
|
||||
dashedName: step-12
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
After your `h2` element, create two `p` elements. Give the first a `class` of `dessert-price`, and the text of the `price` variable with a dollar sign in front of it. Give the second a `class` of `product-category`, and the text `Category:` followed by the value of the `category` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create two `p` elements.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children.length, 3);
|
||||
assert.equal(document.querySelector('.dessert-card')?.querySelectorAll('p')?.length, 2)
|
||||
```
|
||||
|
||||
Your `p` elements should come after your `h2` element.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[0].tagName, 'H2');
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[1].tagName, 'P');
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[2].tagName, 'P');
|
||||
```
|
||||
|
||||
Your first `p` element should have a `class` of `dessert-price`.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[1].className, 'dessert-price');
|
||||
```
|
||||
|
||||
Your first `p` element should have the text of the `price` variable with a dollar sign in front of it.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[1].textContent, '$12.99');
|
||||
```
|
||||
|
||||
Your second `p` element should have a `class` of `product-category`.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[2].className, 'product-category');
|
||||
```
|
||||
|
||||
Your second `p` element should have the text `Category:` followed by the value of the `category` variable.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card')?.children[2].textContent, 'Category: Cupcake');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,304 @@
|
||||
---
|
||||
id: 63ee5e0f08e82208364c4128
|
||||
title: Step 13
|
||||
challengeType: 0
|
||||
dashedName: step-13
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Finally, after your `p` elements, create a `button` element. Give it an `id` set to the value of the `id` variable, a `class` of `btn add-to-cart-btn`, and use `Add to cart` for the text.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `button` element.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelectorAll('.dessert-card button')?.length, 12);
|
||||
```
|
||||
|
||||
Your `button` element should come after your `p` elements.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card button')?.previousElementSibling?.tagName, 'P');
|
||||
assert.isNull(document.querySelector('.dessert-card button')?.nextElementSibling);
|
||||
```
|
||||
|
||||
Your `button` element should have an `id` set to the value of the `id` variable.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card button')?.id, '1');
|
||||
```
|
||||
|
||||
Your `button` element should have a `class` of `btn add-to-cart-btn`.
|
||||
|
||||
```js
|
||||
assert.include(document.querySelector('.dessert-card button')?.className, 'btn');
|
||||
assert.include(document.querySelector('.dessert-card button')?.className, 'add-to-cart-btn');
|
||||
```
|
||||
|
||||
Your `button` element should have the text `Add to cart`.
|
||||
|
||||
```js
|
||||
assert.equal(document.querySelector('.dessert-card button')?.textContent?.trim(), 'Add to cart');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,303 @@
|
||||
---
|
||||
id: 63ee5ea8be892e0955ab346c
|
||||
title: Step 14
|
||||
challengeType: 0
|
||||
dashedName: step-14
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You are already familiar with an HTML `class`, but JavaScript also has a <dfn>class</dfn>. In JavaScript, a class is like a blueprint for creating objects. It allows you to define a set of properties and methods, and instantiate (or create) new objects with those properties and methods.
|
||||
|
||||
The `class` keyword is used to declare a class. Here is an example of declaring a `Computer` class:
|
||||
|
||||
```js
|
||||
class Computer {};
|
||||
```
|
||||
|
||||
Declare a `ShoppingCart` class.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `ShoppingCart` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /ShoppingCart/);
|
||||
```
|
||||
|
||||
You should use the `class` keyword to declare a `ShoppingCart` class.
|
||||
|
||||
```js
|
||||
assert.match(code, /class\s+ShoppingCart\s*/);
|
||||
```
|
||||
|
||||
Your `ShoppingCart` class should be empty.
|
||||
|
||||
```js
|
||||
assert.match(code, /class\s+ShoppingCart\s*\{\s*\}/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,300 @@
|
||||
---
|
||||
id: 63ee5fc113bcb20a5db9214b
|
||||
title: Step 15
|
||||
challengeType: 0
|
||||
dashedName: step-15
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Classes have a special `constructor` method, which is called when a new instance of the class is created. The `constructor` method is a great place to initialize properties of the class. Here is an example of a class with a `constructor` method:
|
||||
|
||||
```js
|
||||
class Computer {
|
||||
constructor() {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Add an empty `constructor` method to the `ShoppingCart` class.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add a `constructor` method to the `ShoppingCart` class.
|
||||
|
||||
```js
|
||||
assert.match(code, /class\s+ShoppingCart\s*\{\s*constructor\(\s*\)\s*/)
|
||||
```
|
||||
|
||||
Your `constructor` method should be empty.
|
||||
|
||||
```js
|
||||
assert.match(code, /class\s+ShoppingCart\s*\{\s*constructor\(\s*\)\s*\{\s*\}\s*\}/)
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
class ShoppingCart {
|
||||
|
||||
};
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,316 @@
|
||||
---
|
||||
id: 63ee611d478dca0b77f6a393
|
||||
title: Step 16
|
||||
challengeType: 0
|
||||
dashedName: step-16
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `this` keyword in JavaScript is used to refer to the current object. Depending on where `this` is used, what it references changes. In the case of a class, it refers to the instance of the object being constructed. You can use the `this` keyword to set the properties of the object being instantiated. Here is an example:
|
||||
|
||||
```js
|
||||
class Computer {
|
||||
constructor() {
|
||||
this.ram = 16;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In your constructor, use the `this` keyword to set the `items` property to an empty array. Also, set the `total` property to `0`, and the `taxRate` property to `8.25`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `this` keyword to set the `items` property of your class to an empty array.
|
||||
|
||||
```js
|
||||
assert.match(code, /this\.items/);
|
||||
const cart = new ShoppingCart();
|
||||
assert.isArray(cart.items);
|
||||
assert.isEmpty(cart.items);
|
||||
```
|
||||
|
||||
You should use the `this` keyword to set the `total` property of your class to `0`.
|
||||
|
||||
```js
|
||||
assert.match(code, /this\.total/);
|
||||
const cart = new ShoppingCart();
|
||||
assert.equal(cart.total, 0);
|
||||
```
|
||||
|
||||
You should use the `this` keyword to set the `taxRate` property of your class to `8.25`.
|
||||
|
||||
```js
|
||||
assert.match(code, /this\.taxRate/);
|
||||
const cart = new ShoppingCart();
|
||||
assert.equal(cart.taxRate, 8.25);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
|
||||
}
|
||||
};
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,321 @@
|
||||
---
|
||||
id: 63ee7c664f9b65137d925c8a
|
||||
title: Step 17
|
||||
challengeType: 0
|
||||
dashedName: step-17
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Your `ShoppingCart` class needs the ability to add items. Create an empty `addItem` method, which takes two parameters: `id` and `products`. Creating a method might look like this:
|
||||
|
||||
```js
|
||||
class Computer {
|
||||
constructor() {
|
||||
this.ram = 16;
|
||||
}
|
||||
|
||||
addRam(amount) {
|
||||
this.ram += amount;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The first parameter, `id`, is the `id` of the product the user has added to their cart. The second parameter, `products`, is an array of product objects. By using a parameter instead of directly referencing your existing `products` array, this method will be more flexible if you wanted to add additional product lists in the future.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `ShoppingCart` class should have an `addItem` method.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.isFunction(cart.addItem);
|
||||
```
|
||||
|
||||
Your `addItem` method should take two parameters: `id` and `products`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /\(\s*id\s*,\s*products\s*\)/);
|
||||
```
|
||||
|
||||
Your `addItem` method should be empty.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /\(\s*id\s*,\s*products\s*\)\s*\{\s*\}/);
|
||||
```
|
||||
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
--fcc-editable-region--
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,331 @@
|
||||
---
|
||||
id: 63eea5cea403a81a68ae493c
|
||||
title: Step 18
|
||||
challengeType: 0
|
||||
dashedName: step-18
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need to find the product that the user is adding to the cart. Remember that arrays have a `.find()` method. In your `addItem` function, declare a `product` variable, and assign it the value of calling the `.find()` method on the `products` array.
|
||||
|
||||
For the callback to `.find()`, pass a function that takes a single parameter `item`, and returns whether the `id` property of `item` is strictly equal to the `id` parameter passed to `addItem`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `product` variable in your `addItem` function.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /product\s*=/);
|
||||
```
|
||||
|
||||
You should call the `.find()` method on your `products` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /products\.find\(/);
|
||||
```
|
||||
|
||||
You should pass a callback function to the `.find()` method.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /products\.find\(\s*function\s*\(/);
|
||||
```
|
||||
|
||||
The callback function should take a single parameter.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /products\.find\(\s*function\s*\(\s*item\s*\)/);
|
||||
```
|
||||
|
||||
The callback function should return whether the `id` property of `item` is strictly equal to the `id` parameter passed to `addItem`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /products\.find\(\s*function\s*\(\s*item\s*\)\s*\{\s*return\s+item\.id\s*===\s*id\s*;?\s*\}/);
|
||||
```
|
||||
|
||||
You should assign the value of the `.find()` method to the `product` variable.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /product\s*=\s*products\.find\(/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,309 @@
|
||||
---
|
||||
id: 63eea817673c8e1c22927fa6
|
||||
title: Step 19
|
||||
challengeType: 0
|
||||
dashedName: step-19
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Use `const` and destructuring to extract `name` and `price` variables from `product`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use destructuring to get the `name` and `price` variables.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /\{\s*name\s*,\s*price\s*\}/);
|
||||
```
|
||||
|
||||
You should use `const` to declare the `name` and `price` variables.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s*\{\s*name\s*,\s*price\s*\}/);
|
||||
```
|
||||
|
||||
You should use destructuring to get the `name` and `price` variables from `product`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s*\{\s*name\s*,\s*price\s*\}\s*=\s*product;?\b/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,311 @@
|
||||
---
|
||||
id: 63eea8e1e143ae1d098c8c9d
|
||||
title: Step 20
|
||||
challengeType: 0
|
||||
dashedName: step-20
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you need to push the `product` into the cart's `items` array. Remember to use the `this` keyword.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call the `push` method on the `items` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /items\.push\(/);
|
||||
```
|
||||
|
||||
Remember you need to use the `this` keyword to access the `items` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /this\.items\.push\(/);
|
||||
```
|
||||
|
||||
You should `push` the `product` variable to the `items` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
assert.deepEqual(cart.items, [products[0]]);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,312 @@
|
||||
---
|
||||
id: 63eeb8e86becbf1e75c2cb0d
|
||||
title: Step 21
|
||||
challengeType: 0
|
||||
dashedName: step-21
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You now need a total count of each product that the user has in the cart. Declare a `totalCountPerProduct` variable, and assign it an empty object.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `totalCountPerProduct` variable in your `addItem` function.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\s*=/);
|
||||
```
|
||||
|
||||
You should use `const` to declare `totalCountPerProduct`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s+totalCountPerProduct\s*=/);
|
||||
```
|
||||
|
||||
You should assign an empty object to `totalCountPerProduct`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s+totalCountPerProduct\s*=\s*\{\s*\}/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,327 @@
|
||||
---
|
||||
id: 63eedebb0ec0231ff1cede1a
|
||||
title: Step 22
|
||||
challengeType: 0
|
||||
dashedName: step-22
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Use the `.forEach()` method to loop through the `items` array. Pass an empty callback function that takes a single parameter `dessert`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `.forEach()` method on your `items` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /items\.forEach\(/);
|
||||
```
|
||||
|
||||
Remember to use the `this` keyword to access the `items` array.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /this\.items\.forEach\(/);
|
||||
```
|
||||
|
||||
You should pass a callback function to the `.forEach()` method.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /this\.items\.forEach\(\s*function\s*\(/);
|
||||
```
|
||||
|
||||
Your callback function should take a single parameter.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /this\.items\.forEach\(\s*function\s*\(\s*dessert\s*\)/);
|
||||
```
|
||||
|
||||
Your callback function should be empty.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /this\.items\.forEach\(\s*function\s*\(\s*dessert\s*\)\s*\{\s*\}/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,323 @@
|
||||
---
|
||||
id: 63efdbc22a0c56070beabed7
|
||||
title: Step 23
|
||||
challengeType: 0
|
||||
dashedName: step-23
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In your `forEach` callback, you need to update the `totalCountPerProduct` object. Using the `id` of the current `dessert` as your property, update the value of the property to be the current value plus one. Do not use the addition assignment operator for this.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use dot notation to access the `id` property of `dessert`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /dessert\.id/);
|
||||
```
|
||||
|
||||
You should use bracket notation to access the property of `totalCountPerProduct` that corresponds to `dessert.id`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]/);
|
||||
```
|
||||
|
||||
You should use the assignment operator to update the value of the property of `totalCountPerProduct` that corresponds to `dessert.id`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=/);
|
||||
```
|
||||
|
||||
You should update the value of `totalCountPerProduct` to be the current value plus one.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=\s*totalCountPerProduct\[\s*dessert\.id\s*\]\s*\+\s*1/);
|
||||
```
|
||||
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
|
||||
})
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,324 @@
|
||||
---
|
||||
id: 63efe370bbfc4a08d500118e
|
||||
title: Step 24
|
||||
challengeType: 0
|
||||
dashedName: step-24
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You now have a small bug. When you try to access a property of an object and the property doesn't exist, you get `undefined`. This means if the dessert isn't already present in the `totalCountPerProduct` object, you end up trying to add `1` to `undefined`, which results in `NaN`.
|
||||
|
||||
To fix this, you can use the `||` operator to set the value to `0` if it doesn't exist. Wrap your right-hand `totalCountPerProduct[data.id]` in parentheses, and add `|| 0` to the end of the expression.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should wrap your right-hand `totalCountPerProduct[data.id]` in parentheses.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=\s*\(\s*totalCountPerProduct\[\s*dessert\.id\s*\]/);
|
||||
```
|
||||
|
||||
You should use the `||` operator.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=\s*\(\s*totalCountPerProduct\[\s*dessert\.id\s*\]\s*\|\|\s*/);
|
||||
```
|
||||
|
||||
You should use `0` as your fallback value.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=\s*\(\s*totalCountPerProduct\[\s*dessert\.id\s*\]\s*\|\|\s*0\s*\)/);
|
||||
```
|
||||
|
||||
You should still add `1` to the value.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /totalCountPerProduct\[\s*dessert\.id\s*\]\s*=\s*\(\s*totalCountPerProduct\[\s*dessert\.id\s*\]\s*\|\|\s*0\s*\)\s*\+\s*1/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = totalCountPerProduct[dessert.id] + 1;
|
||||
})
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,317 @@
|
||||
---
|
||||
id: 63eff02f00e69a0b2ac10b43
|
||||
title: Step 25
|
||||
challengeType: 0
|
||||
dashedName: step-25
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you need to get prepared to update the display with the new product the user added. Declare a `currentProductCount` variable, and assign it the value of the `totalCountPerProduct` object's property matching the `id` of `product`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `currentProductCount` variable in your `addItem` function.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*=/);
|
||||
```
|
||||
|
||||
You should use `const` to declare `currentProductCount`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s+currentProductCount\s*=/);
|
||||
```
|
||||
|
||||
You should assign the value of `totalCountPerProduct[product.id]` to `currentProductCount`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*=\s*totalCountPerProduct\[product\.id\]/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,336 @@
|
||||
---
|
||||
id: 63eff98ffb1d5a0d24ec79cb
|
||||
title: Step 26
|
||||
challengeType: 0
|
||||
dashedName: step-26
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You haven't written the code to generate the HTML yet, but if a product has already been added to the user's cart then there will be a matching element which you'll need.
|
||||
|
||||
Use `.getElementById()` to get the matching element - you'll be setting the `id` value to `product-count-for-id${product.id}`, so use a template literal to query that value.
|
||||
|
||||
Assign your query to a `currentProductCountSpan` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `currentProductCountSpan` variable.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCountSpan\s*=/);
|
||||
```
|
||||
|
||||
You should use `const` to declare `currentProductCountSpan`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /const\s+currentProductCountSpan\s*=/);
|
||||
```
|
||||
|
||||
You should use `document.getElementById()` to get the matching element.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /document\.getElementById\(/);
|
||||
```
|
||||
|
||||
You should use a template literal to query the `id` value.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /document\.getElementById\(\s*`product-count-for-id\$\{(product\.)?id\}`\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the value of `document.getElementById()` to `currentProductCountSpan`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCountSpan\s*=\s*document\.getElementById\(/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,327 @@
|
||||
---
|
||||
id: 63effe558c87a70e7072e447
|
||||
title: Step 27
|
||||
challengeType: 0
|
||||
dashedName: step-27
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The behaviour of the `addItem` method needs to change if the product is already in the cart or not. Create a ternary that checks if the current product is already in the cart. Use `undefined` for both the truthy and falsy expressions to avoid a syntax error.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should check if `currentProductCount` is greater than `1`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*>\s*1/);
|
||||
```
|
||||
|
||||
You should use a ternary operator with your `currentProductCount > 1` condition.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*>\s*1\s*\?/);
|
||||
```
|
||||
|
||||
You should use `undefined` as the truthy expression.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*>\s*1\s*\?\s*undefined/);
|
||||
```
|
||||
|
||||
You should use `undefined` as the falsy expression.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*>\s*1\s*\?\s*undefined\s*:\s*undefined/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,320 @@
|
||||
---
|
||||
id: 63f0165121a9181342d5bc66
|
||||
title: Step 28
|
||||
challengeType: 0
|
||||
dashedName: step-28
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
For your truthy expression, removing the `undefined`, you need to update the `textContent` of the `currentProductCountSpan` to be the `currentProductCount` followed by an `x`. Use a template literal to do so.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should remove the `undefined` from your truthy expression.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.notMatch(cart.addItem.toString(), /currentProductCount\s*>\s*1\s*\?\s*undefined/);
|
||||
```
|
||||
|
||||
You should access the `textContent` property of `currentProductCountSpan`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /currentProductCount\s*>\s*1\s*\?\s*currentProductCountSpan\.textContent/);
|
||||
```
|
||||
|
||||
You should use template literal syntax to update the `textContent` to be `${currentProductCount}x`.
|
||||
|
||||
```js
|
||||
const afterAdd = code.split("addItem")[1];
|
||||
assert.match(afterAdd, /currentProductCount\s*>\s*1\s*\?\s*currentProductCountSpan\.textContent\s*=\s*`\$\{currentProductCount\}x`\s*:/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1 ? undefined : undefined;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,345 @@
|
||||
---
|
||||
id: 63f017b4ad028a148eb713c0
|
||||
title: Step 29
|
||||
challengeType: 0
|
||||
dashedName: step-29
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
For your falsy expression, you'll need to add new HTML to your `productsContainer`. Start by removing the `undefined`, then use the addition assignment operator and template literal syntax to add a `div` with the `class` set to `product` and the `id` set to `dessert${id}` to the `innerHTML` property of the `productsContainer`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should remove the `undefined` from your falsy expression.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.notMatch(cart.addItem.toString(), /undefined/);
|
||||
```
|
||||
|
||||
You should use the addition assignment operator to add HTML to the `productsContainer`. Remember that HTML goes in the `innerHTML` property.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
assert.match(cart.addItem.toString(), /productsContainer\.innerHTML\s*\+=\s*/);
|
||||
```
|
||||
|
||||
You should use template literal syntax to add HTML to the `productsContainer`.
|
||||
|
||||
```js
|
||||
assert.match(code, /productsContainer\.innerHTML\s*\+=\s*`/);
|
||||
```
|
||||
|
||||
You should add a `div` to the `productsContainer`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
assert.equal(productsContainer.children?.[0]?.tagName, "DIV");
|
||||
```
|
||||
|
||||
Your `div` should have the `class` set to `product`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
assert.equal(productsContainer.children?.[0]?.className, "product");
|
||||
```
|
||||
|
||||
Your `div` should have the `id` set to `dessert${id}`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
assert.equal(productsContainer.children?.[0]?.id, "dessert1");
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: undefined;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,325 @@
|
||||
---
|
||||
id: 63f01861f813e01564c95315
|
||||
title: Step 30
|
||||
challengeType: 0
|
||||
dashedName: step-30
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Inside your `div`, add two `p` elements. Set the text of the second `p` element to be the value of the `price` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add two `p` elements inside your `div` element.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
assert.equal(div?.children.length, 2);
|
||||
assert.equal(div?.children[0].tagName, 'P');
|
||||
assert.equal(div?.children[1].tagName, 'P');
|
||||
```
|
||||
|
||||
Your second `p` element should have the text of the `price` variable.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
assert.equal(div?.children[1].textContent, '12.99');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,349 @@
|
||||
---
|
||||
id: 63f018f04e487e164dc27bd9
|
||||
title: Step 31
|
||||
challengeType: 0
|
||||
dashedName: step-31
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In your first `p` element, add a `span` element. Give the `span` a class of `product-count` and an `id` of `product-count-for-id${id}`. Then, after the span, give your `p` element the text of the `name` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your first `p` element should have a `span` element.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
const p = div.querySelector('p');
|
||||
assert.equal(p.children.length, 1);
|
||||
assert.equal(p.children[0].tagName, 'SPAN');
|
||||
```
|
||||
|
||||
Your `span` element should have a `class` of `product-count`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
const p = div.querySelector('p');
|
||||
assert.equal(p.children[0].className, 'product-count');
|
||||
```
|
||||
|
||||
Your `span` element should have an `id` of `product-count-for-id${id}`.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
const p = div.querySelector('p');
|
||||
assert.equal(p.children[0].id, 'product-count-for-id1');
|
||||
```
|
||||
|
||||
Your first `p` element should have the text of the `name` variable. This should be outside the span.
|
||||
|
||||
```js
|
||||
const cart = new ShoppingCart();
|
||||
cart.addItem(1, products);
|
||||
const div = document.querySelector('.product');
|
||||
const p = div.querySelector('p');
|
||||
assert.equal(p.innerText.trim(), 'Vanilla Cupcakes (6 Pack)');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,334 @@
|
||||
---
|
||||
id: 63f01c9791a0aa1751c73760
|
||||
title: Step 32
|
||||
challengeType: 0
|
||||
dashedName: step-32
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
There is still more functionality that your `ShoppingCart` class needs, but first you need to be able to test the code you have currently written. You'll need to <dfn>instantiate</dfn> a new `ShoppingCart` object and assign it to a variable. Here is an example of instantiating the `Computer` class from earlier examples:
|
||||
|
||||
```js
|
||||
const myComputer = new Computer();
|
||||
```
|
||||
|
||||
Declare a `cart` variable, and assign it a new `ShoppingCart` object. Note the use of the `new` keyword when instantiating the object.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `const` to declare a `cart` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+cart\s*=/);
|
||||
```
|
||||
|
||||
You should use the `new` keyword to instantiate a new `ShoppingCart` object.
|
||||
|
||||
```js
|
||||
assert.match(code, /new\s+ShoppingCart\s*\(\s*\)/);
|
||||
```
|
||||
|
||||
You should assign your new `ShoppingCart` object to the `cart` variable.
|
||||
|
||||
```js
|
||||
assert.isTrue(cart instanceof ShoppingCart);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,335 @@
|
||||
---
|
||||
id: 63f0224ceb16dc196d2c860a
|
||||
title: Step 33
|
||||
challengeType: 0
|
||||
dashedName: step-33
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need to get all of the `Add to cart` buttons that you added to the DOM earlier. Declare an `addToCartBtns` variable, and assign it the value of calling the `getElementsByClassName()` method on the `document` object, passing in the string `add-to-cart-btn`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use `const` to declare your `addToCartBtns` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /const\s+addToCartBtns\s*=/);
|
||||
```
|
||||
|
||||
You should call the `getElementsByClassName()` method on the `document` object.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\s*\.\s*getElementsByClassName\s*\(/);
|
||||
```
|
||||
|
||||
You should pass the string `add-to-cart-btn` to the `getElementsByClassName()` method.
|
||||
|
||||
```js
|
||||
assert.match(code, /document\s*\.\s*getElementsByClassName\s*\(\s*('|"|`)add-to-cart-btn\1\s*\)/);
|
||||
```
|
||||
|
||||
You should assign the value returned by the `getElementsByClassName()` method to the `addToCartBtns` variable.
|
||||
|
||||
```js
|
||||
assert.deepEqual(addToCartBtns, document.getElementsByClassName('add-to-cart-btn'));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,339 @@
|
||||
---
|
||||
id: 63f026d041bc6c1a3d5cba0f
|
||||
title: Step 34
|
||||
challengeType: 0
|
||||
dashedName: step-34
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need to iterate through the buttons in your `addToCartBtns` variable. However, `.getElementsByClassName()` returns a Collection, which does not have a `forEach` method.
|
||||
|
||||
Use the spread operator on the `addToCartBtns` variable to convert it into an array. Then, use the `forEach` method to iterate through the array. Do not pass a callback function yet.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the spread operator on the `addToCartBtns` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /\.\.\.addToCartBtns/);
|
||||
```
|
||||
|
||||
You should spread the `addToCartBtns` variable into an array.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]/);
|
||||
```
|
||||
|
||||
You should use the `forEach` method on the array you created.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(/);
|
||||
```
|
||||
|
||||
You should not pass a callback function to the `forEach` method.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,339 @@
|
||||
---
|
||||
id: 63f0284532742c1b26c7a052
|
||||
title: Step 35
|
||||
challengeType: 0
|
||||
dashedName: step-35
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Add your callback function to the `forEach` method. It should take a `btn` parameter. Then, in the callback, add an event listener to the `btn`. The event listener should listen for a `click` event, and should take another callback with an `event` parameter. The second callback should be empty.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use arrow syntax to add a callback function to the `forEach` method which takes a `btn` parameter.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(\s*\(?\s*btn\s*\)?\s*=>\s*\{/);
|
||||
```
|
||||
|
||||
You should add an event listener to the `btn` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(\s*\(?\s*btn\s*\)?\s*=>\s*\{\s*btn\s*\.\s*addEventListener\s*\(/);
|
||||
```
|
||||
|
||||
You should listen for a `click` event on the `btn` variable.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(\s*\(?\s*btn\s*\)?\s*=>\s*\{\s*btn\s*\.\s*addEventListener\s*\(\s*('|"|`)click\1\s*,\s*/);
|
||||
```
|
||||
|
||||
You should add an empty callback function to the event listener. Remember to give it an `event` parameter.
|
||||
|
||||
```js
|
||||
assert.match(code, /\[\s*\.\.\.addToCartBtns\s*\]\s*\.\s*forEach\s*\(\s*\(?\s*btn\s*\)?\s*=>\s*\{\s*btn\s*\.\s*addEventListener\s*\(\s*('|"|`)click\1\s*,\s*\(\s*event\s*\)\s*=>\s*\{\s*\}\s*\)\s*\s*\}\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
--fcc-editable-region--
|
||||
[...addToCartBtns].forEach(
|
||||
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,339 @@
|
||||
---
|
||||
id: 63f0289df84a581bbdbd29b7
|
||||
title: Step 36
|
||||
challengeType: 0
|
||||
dashedName: step-36
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In your event listener callback, call the `.addItem()` method of your `cart` object, and pass in the `event.target.id`. Remember that the `id` here will be a string, so you need to convert it to a number.
|
||||
|
||||
Pass your `products` array as the second argument.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your event listener callback should call the `.addItem()` method of your `cart` object.
|
||||
|
||||
```js
|
||||
assert.match(code, /cart\.addItem\(/);
|
||||
```
|
||||
|
||||
Your `.addItem()` method should be called with the `event.target.id` as the first argument. Remember to convert the `id` to a number using `Number()`.
|
||||
|
||||
```js
|
||||
assert.match(code, /cart\.addItem\(\s*Number\(\s*event\.target\.id\s*\)\s*/);
|
||||
```
|
||||
|
||||
Your `.addItem()` method should be called with the `products` array as the second argument.
|
||||
|
||||
```js
|
||||
assert.match(code, /cart\.addItem\(\s*Number\(\s*event\.target\.id\s*\)\s*,\s*products\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<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>freeCodeCamp Shopping Cart</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1 class="title">Desserts Page</h1>
|
||||
</header>
|
||||
<main>
|
||||
<button id="cart-btn" type="button" class="btn">
|
||||
<span id="show-hide-cart">Show</span> Cart
|
||||
</button>
|
||||
<div id="cart-container">
|
||||
<button class="btn" id="clear-cart-btn">Clear Cart</button>
|
||||
<div id="products-container"></div>
|
||||
<p>Total number of items: <span id="total-items">0</span></p>
|
||||
<p>Subtotal: <span id="subtotal">$0</span></p>
|
||||
<p>Taxes: <span id="taxes">$0</span></p>
|
||||
<p>Total: <span id="total">$0</span></p>
|
||||
</div>
|
||||
<div id="dessert-card-container"></div>
|
||||
</main>
|
||||
<script src="./script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--dark-grey: #1b1b32;
|
||||
--light-grey: #f5f6f7;
|
||||
--black: #000;
|
||||
--white: #fff;
|
||||
--grey: #3b3b4f;
|
||||
--golden-yellow: #fecc4c;
|
||||
--yellow: #ffcc4c;
|
||||
--gold: #feac32;
|
||||
--orange: #ffac33;
|
||||
--dark-orange: #f89808;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--dark-grey);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--light-grey);
|
||||
text-align: center;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
#dessert-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
background-color: var(--light-grey);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.dessert-price {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
color: var(--dark-grey);
|
||||
background-color: var(--gold);
|
||||
background-image: linear-gradient(var(--golden-yellow), var(--orange));
|
||||
border-color: var(--gold);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-image: linear-gradient(var(--yellow), var(--dark-orange));
|
||||
}
|
||||
|
||||
#cart-btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.add-to-cart-btn {
|
||||
margin: 30px auto 10px;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
background-color: var(--light-grey);
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
border: 8px double var(--black);
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.product {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.product-count {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.product-category {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dessert-card-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dessert-card {
|
||||
flex: 1 0 21%;
|
||||
}
|
||||
|
||||
#cart-container {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const cartContainer = document.getElementById("cart-container");
|
||||
const productsContainer = document.getElementById("products-container");
|
||||
const dessertCards = document.getElementById("dessert-card-container");
|
||||
const cartBtn = document.getElementById("cart-btn");
|
||||
const clearCartBtn = document.getElementById("clear-cart-btn");
|
||||
const totalNumberOfItems = document.getElementById("total-items");
|
||||
const cartSubTotal = document.getElementById("subtotal");
|
||||
const cartTaxes = document.getElementById("taxes");
|
||||
const cartTotal = document.getElementById("total");
|
||||
const showHideCartSpan = document.getElementById("show-hide-cart");
|
||||
let isCartShowing = false;
|
||||
|
||||
const products = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Vanilla Cupcakes (6 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "French Macaroon",
|
||||
price: 3.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Pumpkin Cupcake",
|
||||
price: 3.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Chocolate Cupcake",
|
||||
price: 5.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Chocolate Pretzels (4 Pack)",
|
||||
price: 10.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Strawberry Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Chocolate Macaroons (4 Pack)",
|
||||
price: 9.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Strawberry Pretzel",
|
||||
price: 4.99,
|
||||
category: "Pretzel",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Butter Pecan Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Rocky Road Ice Cream",
|
||||
price: 2.99,
|
||||
category: "Ice Cream",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Vanilla Macaroons (5 Pack)",
|
||||
price: 11.99,
|
||||
category: "Macaroon",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Lemon Cupcakes (4 Pack)",
|
||||
price: 12.99,
|
||||
category: "Cupcake",
|
||||
},
|
||||
];
|
||||
|
||||
products.forEach(
|
||||
({ name, id, price, category }) => {
|
||||
dessertCards.innerHTML += `
|
||||
<div class="dessert-card">
|
||||
<h2>${name}</h2>
|
||||
<p class="dessert-price">$${price}</p>
|
||||
<p class="product-category">Category: ${category}</p>
|
||||
<button
|
||||
id="${id}"
|
||||
class="btn add-to-cart-btn">Add to cart
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
);
|
||||
|
||||
class ShoppingCart {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
this.total = 0;
|
||||
this.taxRate = 8.25;
|
||||
}
|
||||
|
||||
addItem(id, products) {
|
||||
const product = products.find((item) => item.id === id);
|
||||
const { name, price } = product;
|
||||
this.items.push(product);
|
||||
|
||||
const totalCountPerProduct = {};
|
||||
this.items.forEach((dessert) => {
|
||||
totalCountPerProduct[dessert.id] = (totalCountPerProduct[dessert.id] || 0) + 1;
|
||||
})
|
||||
|
||||
const currentProductCount = totalCountPerProduct[product.id];
|
||||
const currentProductCountSpan = document.getElementById(`product-count-for-id${id}`);
|
||||
|
||||
currentProductCount > 1
|
||||
? currentProductCountSpan.textContent = `${currentProductCount}x`
|
||||
: productsContainer.innerHTML += `
|
||||
<div id=dessert${id} class="product">
|
||||
<p>
|
||||
<span class="product-count" id=product-count-for-id${id}></span>${name}
|
||||
</p>
|
||||
<p>${price}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
const cart = new ShoppingCart();
|
||||
const addToCartBtns = document.getElementsByClassName("add-to-cart-btn");
|
||||
|
||||
--fcc-editable-region--
|
||||
[...addToCartBtns].forEach(
|
||||
(btn) => {
|
||||
btn.addEventListener("click", (event) => {
|
||||
|
||||
})
|
||||
}
|
||||
);
|
||||
--fcc-editable-region--
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user