diff --git a/src/2week/app.js b/src/2week/app.js
index f20346a..a410af0 100644
--- a/src/2week/app.js
+++ b/src/2week/app.js
@@ -1,68 +1,151 @@
-var shopping_cart = [];
-var shopping_cart_total = 0;
+import ShoppingCart from './cart.js';
-document.querySelectorAll('button').forEach(button =>
- button.addEventListener('click', ({ target }) => {
- const name = target.parentNode.querySelector('.menu-name').textContent;
- const category = target.parentNode.querySelector('.category').textContent;
- const price = target.parentNode.querySelector('.price').textContent;
+const {
+ cartGetter: getCart,
+ cartTotalGetter: getCartTotal,
+ cartSetter: setCart,
+} = ShoppingCart();
+
+const cartLayer = document.getElementById('cart-layer');
+const cartIcon = document.querySelector('.carts>.icons');
+const productList = document.querySelector('.items');
+
+cartIcon.addEventListener('click', () => {
+ show_dom(cartLayer);
+ set_cart_list_dom();
+});
- add_item_to_cart({ name, category, price });
- }),
+cartLayer.addEventListener('click', (e) => {
+ if (e.target !== cartLayer) return;
+ hide_dom(cartLayer);
+});
+
+productList.querySelectorAll('.add-to-cart').forEach((button) =>
+ button.addEventListener('click', ({ target }) => {
+ setCart('add', makeCartItem(target.parentNode));
+ update_shipping_icons_dom(getCartTotal());
+ set_total_price_dom(getCartTotal());
+ })
);
-function add_item_to_cart(item) {
- shopping_cart.push(item);
- console.log(shopping_cart);
- calc_cart_total();
+// action - dom : get_dom_value 호출
+function makeCartItem(targetProduct = document) {
+ const PRODUCT_KEYS = [
+ {
+ type: 'string',
+ className: 'category',
+ },
+ {
+ type: 'number',
+ className: 'price',
+ },
+ {
+ type: 'string',
+ className: 'menu-name',
+ },
+ ];
+
+ const cartItem = {};
+ PRODUCT_KEYS.forEach((key) => {
+ cartItem[key.className] = get_dom_value(
+ key.className,
+ key.type,
+ targetProduct
+ );
+ });
+ return cartItem;
+}
+
+// action - dom : get_buy_buttons_dom 호출
+function update_shipping_icons_dom(total) {
+ const buy_buttons = get_buy_buttons_dom();
+ buy_buttons.forEach((btn) => {
+ const btn_item_price = get_dom_value('price', 'number', btn.parentNode);
+ if (is_free_shipping(btn_item_price, total)) btn.show_free_shipping_icon();
+ else btn.hide_free_shipping_icon();
+ });
}
-function calc_cart_total() {
- shopping_cart_total = 0;
- for (var i = 0; i < shopping_cart.length; i++) {
- var item = shopping_cart[i];
- shopping_cart_total += item.price;
+// action - dom [dynamicSelector]
+function get_dom_value(className, valueType, target = document) {
+ const el = target.querySelector(`.${className}`);
+ if (!el) return null;
+
+ if (valueType === 'string') {
+ return el.textContent;
+ } else {
+ return formatToNumber(el.textContent);
}
- set_cart_total_dom();
- update_shipping_icons();
- update_tax_dom();
}
-function set_cart_total_dom() {
- document.querySelector('.total-price').textContent = shopping_cart_total;
+// action - dom 'cart-list'
+function set_cart_list_dom() {
+ const cartList = document.getElementById('cart-list');
+ cartList.innerHTML = getCart()
+ .map(
+ (item) => `
+
+
${item.category}
+
${item['menu-name']}
+
${formatNumberToCurrency(item.price)}
+
+ `
+ )
+ .join('');
}
-function update_shipping_icons() {
- var buy_buttons = get_buy_buttons_dom();
- for (var i = 0; i < buy_buttons.length; i++) {
- var item = buy_buttons[i];
- console.log(item);
- if (item.price + shopping_cart_total >= 20) item.show_free_shopping_icon();
- else item.hide_free_shopping_icon();
- }
+// action - dom 'total-price'
+function set_total_price_dom(total) {
+ document.querySelector('.total-price').textContent = formatNumberToCurrency(
+ total + calc_tax(total)
+ );
}
+// action - dom 'add-to-cart'
function get_buy_buttons_dom() {
- var buttons = [];
-
- for (var i = 0; i < shopping_cart.length; i++) {
- var item = shopping_cart[i];
- item.show_free_shopping_icon = function () {
- console.log('DOM 의 아이콘을 보여줍니다');
+ const add_to_cart_btns = Array.from(
+ document.querySelectorAll('.add-to-cart')
+ );
+ return add_to_cart_btns.map((btn) => {
+ btn.show_free_shipping_icon = function () {
+ this.parentNode
+ .querySelector('.free-shipping-icon')
+ .classList.remove('hidden');
};
- item.hide_free_shopping_icon = function () {
- console.log('DOM 의 아이콘을 숨깁니다');
+ btn.hide_free_shipping_icon = function () {
+ this.parentNode
+ .querySelector('.free-shipping-icon')
+ .classList.add('hidden');
};
- buttons.push(item);
- }
+ return btn;
+ });
+}
+
+// 비즈니스 - 세금
+function calc_tax(total) {
+ return total * 0.1;
+}
+// 비즈니스 - 배송
+function is_free_shipping(itemPrice, cartTotal) {
+ return itemPrice + cartTotal >= 20000;
+}
+
+// utils ? - DOM
+function show_dom(el) {
+ el.style.display = 'block';
+}
- return buttons;
+// utils ? - DOM
+function hide_dom(el) {
+ el.style.display = 'none';
}
-function update_tax_dom() {
- set_tax_dom(shopping_cart_total * 0.1);
+// utils - format
+function formatToNumber(text) {
+ return parseFloat(text.replace(/[^\d]/g, ''));
}
-function set_tax_dom(value) {
- document.querySelector('.total-price').textContent = value;
+// utils - format
+function formatNumberToCurrency(priceNum) {
+ return priceNum.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') + '원';
}
diff --git a/src/2week/assets/css/app.css b/src/2week/assets/css/app.css
index f95b45b..8361762 100644
--- a/src/2week/assets/css/app.css
+++ b/src/2week/assets/css/app.css
@@ -4,8 +4,8 @@
}
body {
- background-color: #F2EEE9;
- font: normal 13px/1.5 Georgia, Serif;
+ background-color: #f2eee9;
+ font: normal 13px/1.5 'sans-serif';
color: #333;
}
@@ -67,7 +67,7 @@ button {
border: none;
border-radius: 8px;
padding: 4px 14px;
- background-color: #00A29E;
+ background-color: #00a29e;
color: #ffffff;
text-transform: uppercase;
float: right;
@@ -82,7 +82,7 @@ button {
}
button:hover {
- background-color: #00C6C2;
+ background-color: #00c6c2;
}
button:active {
@@ -93,22 +93,97 @@ span {
float: right;
}
+.hidden {
+ display: none;
+}
+
.shopping-cart {
display: inline-block;
- background: url('http://cdn1.iconfinder.com/data/icons/jigsoar-icons/24/_cart.png') no-repeat 0 0;
+ background: url('http://cdn1.iconfinder.com/data/icons/jigsoar-icons/24/_cart.png')
+ no-repeat 0 0;
width: 24px;
height: 24px;
margin: 0 10px 0 0;
}
+.free-shipping-icon {
+ color: #fff;
+ font-size: 13px;
+ background: #212529;
+ padding: 2px 6px;
+ border-radius: 8px;
+ margin-top: 10px;
+ float: left;
+}
+
.category {
border-radius: 8px;
background-color: #fff;
- border: 1px solid #00A29E;
- color: #00A29E;
+ border: 1px solid #00a29e;
+ color: #00a29e;
padding: 6px;
}
-p, .price {
+p,
+.price {
height: 20px;
-}
\ No newline at end of file
+}
+
+/* cart layer */
+#cart-layer {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #21252940;
+}
+
+#cart-layer_inner {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 40%;
+ height: 100%;
+ background-color: #fff;
+}
+
+#cart-layer_inner > h2 {
+ font-size: large;
+ padding: 16px;
+ margin-bottom: 16px;
+}
+
+#cart-list {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ padding: 16px;
+}
+
+#cart-list .cart-item {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ background-color: #00585760;
+ border-radius: 8px;
+ padding: 16px;
+}
+
+#cart-list .cart-item > .name {
+ width: 100%;
+ font-size: 14px;
+ margin-bottom: 8px;
+}
+
+#cart-list .cart-item > .category {
+ width: 24px;
+ height: 24px;
+}
+
+#cart-list .cart-item > .price {
+ width: 20%;
+ font-weight: 700;
+}
diff --git a/src/2week/cart.js b/src/2week/cart.js
new file mode 100644
index 0000000..d8a615b
--- /dev/null
+++ b/src/2week/cart.js
@@ -0,0 +1,30 @@
+const ShoppingCart = () => {
+ let shopping_cart = [];
+
+ const cartGetter = () => [...shopping_cart];
+
+ const cartTotalGetter = () =>
+ shopping_cart.reduce((acc, item) => acc + item.price, 0);
+
+ const cartSetter = (action, item) => {
+ switch (action) {
+ case 'add':
+ shopping_cart = [...shopping_cart, item];
+ break;
+ case 'update':
+ break;
+ case 'delete':
+ break;
+ default:
+ throw new Error('Action must be one of "add", "update", or "delete"');
+ }
+ };
+
+ return {
+ cartGetter,
+ cartTotalGetter,
+ cartSetter,
+ };
+};
+
+export default ShoppingCart;
diff --git a/src/2week/index.html b/src/2week/index.html
index c4111e9..6476c9a 100644
--- a/src/2week/index.html
+++ b/src/2week/index.html
@@ -2,121 +2,153 @@
-
-
-
+
+
+
FECrash 카페
-
-
+
+
FECrash 카페
-
- 0원
+
+ 0원
+
+

-
C
+
+ C
+
가격: 1,000원
-
+
무료배송
+

-
C
+
+ C
+
-
가격: 3,500원
-
-
+
가격: 3,500원
+
무료배송
+

-
C
+
+ C
+
-
가격: 4,000원
-
+
가격: 4,000원
+
무료배송

-
C
+
+ C
+
-
가격: 3,900원
-
+
가격: 3,900원
+
무료배송

-
C
+
+ C
+
-
가격: 5,200원
-
+
가격: 5,200원
+
무료배송

-
C
+
+ C
+
-
가격: 4,800원
-
+
가격: 4,800원
+
무료배송

-
C
+
+ C
+
-
가격: 4,300원
-
+
가격: 4,300원
+
무료배송

-
C
+
+ C
+
-
가격: 5,500원
-
+
가격: 5,500원
+
무료배송

-
C
+
+ C
+
-
가격: 6,000원
-
+
가격: 6,000원
+
무료배송

-
B
+
+ B
+
-
가격: 7,000원
-
+
가격: 7,000원
+
무료배송

-
B
+
+ B
+
-
가격: 3,300원
-
+
가격: 3,300원
+
무료배송

-
B
+
+ B
+
-
가격: 7,200원
-
+
가격: 7,200원
+
무료배송
-
+
\ No newline at end of file