Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 129 additions & 46 deletions src/2week/app.js
Original file line number Diff line number Diff line change
@@ -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) => `
<div class='cart-item'>
<span class='category'>${item.category}</span>
<h3 class='name'>${item['menu-name']}</h3>
<p class='price'>${formatNumberToCurrency(item.price)}</p>
</div>
`
)
.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, ',') + '원';
}
93 changes: 84 additions & 9 deletions src/2week/assets/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -82,7 +82,7 @@ button {
}

button:hover {
background-color: #00C6C2;
background-color: #00c6c2;
}

button:active {
Expand All @@ -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;
}
}

/* 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;
}
30 changes: 30 additions & 0 deletions src/2week/cart.js
Original file line number Diff line number Diff line change
@@ -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;
Loading