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원
+
+
+

장바구니

+
+
+
+
item -

C오늘의 커피

+

+ C오늘의 커피 +

가격: 1,000원

- + +
item -

C나이트로 바닐라 크림

+

+ C나이트로 바닐라 크림 +

-

가격: 3,500원 -

- +

가격: 3,500원

+ +
item -

C나이트로 콜드 브루

+

+ C나이트로 콜드 브루 +

-

가격: 4,000원 -

+

가격: 4,000원

+
item -

C돌체 콜드 브루

+

+ C돌체 콜드 브루 +

-

가격: 3,900원 -

+

가격: 3,900원

+
item -

C자바 칩 프라푸치노

+

+ C자바 칩 프라푸치노 +

-

가격: 5,200원 -

+

가격: 5,200원

+
item -

C민트 콜드 브루

+

+ C민트 콜드 브루 +

-

가격: 4,800원 -

+

가격: 4,800원

+
item -

C바닐라 크림 콜드 브루

+

+ C바닐라 크림 콜드 브루 +

-

가격: 4,300원 -

+

가격: 4,300원

+
item -

C아이스 토피넛 라떼

+

+ C아이스 토피넛 라떼 +

-

가격: 5,500원 -

+

가격: 5,500원

+
item -

C제주 비저링 콜드 브루

+

+ C제주 비저링 콜드 브루 +

-

가격: 6,000원 -

+

가격: 6,000원

+
item -

B라즈베리 쇼콜라

+

+ B라즈베리 쇼콜라 +

-

가격: 7,000원 -

+

가격: 7,000원

+
item -

B클래식 스콘

+

+ B클래식 스콘 +

-

가격: 3,300원 -

+

가격: 3,300원

+
item -

B티라미수 크림 데니쉬

+

+ B티라미수 크림 데니쉬 +

-

가격: 7,200원 -

+

가격: 7,200원

+
- + \ No newline at end of file