코딩하는 김딸기
카트 js 본문
이 코드는 장바구니와 위시리스트 기능을 구현하는 JavaScript 코드입니다. 주요 기능은 사용자 로그인 상태에 따라 장바구니 정보를 가져오고, 장바구니에 상품을 추가, 삭제, 수량 변경 등을 관리합니다. 각 파트를 기능별로 나누어 자세히 설명하겠습니다.
1. 초기 설정
import axios from 'axios';
let cart = {
items: [],
total: 0,
};
let wishlist = [];
// 이 ID로 로그인하고 있다고 가정하고 TEST 시도중
// let accessToken =
// 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOjUsInR5cGUiOiJ1c2VyIiwibmFtZSI6IkdEIiwiZW1haWwiOiJhcGlAbWFya2V0LmNvbSIsImxvZ2luVHlwZSI6ImVtYWlsIiwiaWF0IjoxNzMwMDc2MDg1LCJleHAiOjE3MzAxNjI0ODUsImlzcyI6IkZFU1AifQ.IwbcsQGQooCY9cReXhCjdomfGlKCPzkBVzMP_ujUiyY'; // 예시로 접근 토큰 저장
let accessToken = null;
- axios: HTTP 요청을 보내기 위한 라이브러리입니다.
- cart: 장바구니 정보를 담고 있는 객체로, items는 장바구니에 담긴 상품 리스트, total은 총합계입니다.
- wishlist: 사용자의 위시리스트를 저장하는 배열입니다.
- accessToken: 로그인 상태를 확인하기 위한 JWT 토큰을 저장합니다.
2. 장바구니 데이터 가져오기
// 장바구니 정보 업데이트
async function fetchCart() {
try {
accessToken = sessionStorage.getItem('accessToken') || null;
let response;
if (accessToken) {
// 로그인한 경우
headers: {
'Content-Type': 'application/json',
'client-id': 'vanilla01',
Authorization: `Bearer ${accessToken}`,
},
});
} else {
// 비로그인 상태인 경우
response = await axios.post(
{
products: [
],
},
{
headers: {
'Content-Type': 'application/json',
'client-id': 'vanilla01',
},
},
);
}
console.log(response.data);
if (
response.data &&
response.data.item &&
Array.isArray(response.data.item)
) {
cart.items = response.data.item;
} else {
cart.items = [];
}
updateCartView();
updateOrderSummary();
} catch (error) {
console.error(
'카트 데이터를 가져오는 데 실패했습니다:',
error.response ? error.response.data : error.message,
);
}
}
- fetchCart(): 장바구니 데이터를 가져오는 비동기 함수입니다.
- accessToken을 세션 스토리지에서 가져옵니다.
- 로그인 상태에 따라 다른 API 요청을 보냅니다. 로그인한 경우 장바구니 데이터를 가져오고, 비로그인 상태에서는 로컬 장바구니를 생성합니다.
- 응답 데이터에서 장바구니 아이템을 가져오고, 이를 cart.items에 저장합니다.
- updateCartView()와 updateOrderSummary() 함수를 호출하여 UI를 업데이트합니다.
3. 장바구니 초기화
function initCart() {
// updateCartView();
fetchCart();
updateWishlistView();
}
- initCart(): 장바구니와 위시리스트를 초기화하는 함수입니다.
- fetchCart()를 호출하여 장바구니 데이터를 가져옵니다.
- updateWishlistView()를 호출하여 위시리스트를 업데이트합니다.
4. 장바구니 뷰 업데이트
function updateCartView() {
const cartItemsContainer = document.getElementById('cart-items');
const emptyCartMessage = document.getElementById('empty-cart-message');
const orderSummary = document.getElementById('order-summary');
if (cart.items.length === 0) {
cartItemsContainer.style.display = 'none';
emptyCartMessage.style.display = 'block';
orderSummary.style.display = 'none';
} else {
cartItemsContainer.style.display = 'block';
emptyCartMessage.style.display = 'none';
orderSummary.style.display = 'block';
cartItemsContainer.innerHTML = cart.items
.map(item => {
// image 속성이 없을 경우 기본 이미지 URL 사용
const imageUrl =
const itemName = item.product.name || '이름 없는 상품';
const itemPrice = (item.product.price || 0).toLocaleString();
const categoryDescription = item.product.extra?.category
? item.product.extra.category.join(', ')
: '';
return `
<div class="cart-item">
<img src="${imageUrl}" alt="${itemName}" onerror="this.onerror=null; this.src='https://via.placeholder.com/150'">
<div class="item-details">
<div class="item-header">
<div class="item-name">${itemName}</div>
<div class="item-price">${itemPrice.toLocaleString()}원</div>
</div>
<div class="item-option">${item.product.color}</div>
<div class="item-description">${categoryDescription}</div>
<div>
<span class="item-size">사이즈 ${item.size}</span>
<div class="quantity-control">
<button class="button-class" onclick="changeQuantity(${
item._id
}, -1)">-</button>
<input type="number" value="${
item.quantity
}" min="1" onchange="updateQuantity(${item._id}, this.value)">
<button class="button-class" onclick="changeQuantity(${
item._id
}, 1)">+</button>
</div>
</div>
<div class="item-actions">
<button class="add-to-wishlist button-class" onclick="addToWishlist(${
item._id
})">
<img src="../../../../public/assets/icons/button36px/white-heart.svg" alt="빈 하트" style="width: 24px; height: auto;"></button>
<button class="remove-item button-class" onclick="removeItem(${item._id
})">
<img src="../../../../public/assets/icons/button36px/delete.svg" alt="삭제" style="width: 20px; height: auto;">
</button>
</div>
</div>
</div>
<div class="delivery-info">
<div class="shipping-fee">${
item.shippingFees
? item.shippingFees.toLocaleString()
: '무료배송'
}</div>
<div class="delivery-details">도착 예정일: ${
item.deliveryDate || '정보 없음'
}
<span class="region-edit"><a href="#">지역 수정</a></span>
</div>
</div>
`;
})
.join('');
cartItemsContainer.querySelectorAll('.decrease').forEach(button => {
button.addEventListener('click', e => {
const itemId = e.target.dataset.id;
changeQuantity(itemId, -1);
});
});
cartItemsContainer.querySelectorAll('.increase').forEach(button => {
button.addEventListener('click', e => {
const itemId = e.target.dataset.id;
changeQuantity(itemId, 1);
});
});
cartItemsContainer.querySelectorAll('.add-to-wishlist').forEach(button => {
button.addEventListener('click', e => {
const itemId = e.target.dataset.id;
addToWishlist(itemId);
});
});
cartItemsContainer.querySelectorAll('.remove-item').forEach(button => {
button.addEventListener('click', e => {
const itemId = e.target.dataset.id;
removeItem(itemId);
});
});
updateOrderSummary();
}
}
- updateCartView(): 장바구니의 UI를 업데이트하는 함수입니다.
- 장바구니에 아이템이 없으면 빈 장바구니 메시지를 표시하고, 있으면 장바구니 내용을 보여줍니다.
- 장바구니 아이템 각각에 대한 HTML을 생성하여 cartItemsContainer에 추가합니다.
- 각 아이템에 대해 수량 조정 버튼과 삭제, 위시리스트 추가 버튼을 포함합니다.
5. 위시리스트 업데이트
function updateWishlistView() {
const wishlistContainer = document.getElementById('wishlist-items');
wishlistContainer.innerHTML = wishlist
.map(item => {
// 이미지 URL과 제품 이름이 정의되어 있는지 체크
const imageUrl =
const productName = item.product?.name || '이름 없는 상품';
const productPrice =
item.product?.price?.toLocaleString() || '가격 정보 없음';
return `
<div class="wishlist-item">
<img src="${imageUrl}" alt="${productName}">
<div class="wishlist-item-details">
<div class="item-name">${productName}</div>
<div class="item-price">${productPrice}원</div>
<button class="add-to-cart-button" onclick="addToCartFromWishlist(${item.product._id})">장바구니에 추가</button>
</div>
</div>
`;
})
.join('');
}
- updateWishlistView(): 위시리스트의 UI를 업데이트하는 함수입니다.
- 위시리스트에 있는 아이템을 HTML로 변환하여 wishlistContainer에 추가합니다.
- 각 아이템은 이미지, 이름, 가격, 장바구니에 추가하는 버튼을 포함합니다.
6. 주문 요약 업데이트
function updateOrderSummary() {
const subtotal = cart.items.reduce(
(sum, item) => sum + item.product.price * item.quantity,
0,
);
document.getElementById('subtotal').textContent =
`${subtotal.toLocaleString()}원`;
document.getElementById('total').textContent =
`${subtotal.toLocaleString()}원`;
}
- updateOrderSummary(): 장바구니의 총합계를 업데이트하는 함수입니다.
- 장바구니에 있는 모든 아이템의 가격을 합산하여 subtotal을 계산합니다.
- subtotal을 HTML 요소에 표시합니다.
7. 수량 변경 및 업데이트
function changeQuantity(itemId, change) {
const item = cart.items.find(i => i._id === itemId);
if (item) {
item.quantity = Math.max(1, item.quantity + change);
updateCartQuantity(itemId, item.quantity);
updateCartView();
}
}
window.changeQuantity = changeQuantity;
function updateQuantity(itemId, newQuantity) {
const item = cart.items.find(i => i._id === itemId);
if (item) {
item.quantity = Math.max(1, parseInt(newQuantity) || 1);
updateCartQuantity(itemId, item.quantity);
updateCartView();
}
}
window.updateQuantity = updateQuantity;
- changeQuantity(): 수량을 증가 또는 감소시키는 함수입니다.
- 특정 아이템의 수량을 변경하고 장바구니 뷰를 업데이트합니다.
- updateQuantity(): 입력 필드에서 직접 수량을 변경하는 함수입니다.
- updateCartQuantity(): 서버에 수량 변경 요청을 보내는 비동기 함수입니다.
1. removeItem(itemId): 장바구니에서 상품 삭제
function removeItem(itemId) {
cart.items = cart.items.filter(item => item._id !== itemId);
deleteCartItem(itemId);
updateCartView();
}
window.removeItem = removeItem;
- 설명: 이 함수는 주어진 itemId와 일치하는 상품을 장바구니에서 제거합니다. 내부적으로 deleteCartItem() 함수를 호출하여 서버에 삭제 요청을 보낸 후, updateCartView() 함수를 호출하여 UI를 업데이트합니다.
2. addToWishlist(itemId): 위시리스트에 상품 추가
function addToWishlist(itemId) {
const item = cart.items.find(i => i._id === itemId);
if (item && !wishlist.some(w => w._id === itemId)) {
wishlist.push({ ...item });
updateWishlistView();
}
}
window.addToWishlist = addToWishlist;
- 설명: 이 함수는 장바구니에서 아이템을 찾아, 위시리스트에 해당 아이템이 없으면 복사하여 추가합니다. 위시리스트 업데이트 후 UI를 갱신합니다.
3. addToCartFromWishlist(productId): 위시리스트에서 장바구니로 추가
function addToCartFromWishlist(productId) {
const item = wishlist.find(i => i.product?._id === productId);
if (item && item.product) {
const existingCartItem = cart.items.find(i => i.product_id === productId); // 수정된 부분
if (existingCartItem) {
existingCartItem.quantity += 1;
} else {
cart.items.push({
_id: item._id,
user_id: item.user_id,
product_id: item.product._id,
quantity: 1,
size: item.size || '미설정',
createdAt: item.createdAt,
updatedAt: item.createdAt,
product: {
...item.product,
image: {
path: item.product.image.url,
name: item.product.image.fileName,
originalname: item.product.image.orgName,
},
},
shippingFees: '무료 배송',
deliveryDate: '7월 26일 (금)',
});
}
updateCartView();
}
}
window.addToCartFromWishlist = addToCartFromWishlist;
- 설명: 위시리스트에서 특정 제품을 찾아 장바구니에 추가합니다. 제품이 이미 장바구니에 존재하면 수량을 증가시키고, 그렇지 않으면 새로 추가합니다. 이후 UI를 갱신합니다.
4. updateCartQuantity(itemId, quantity): 장바구니 수량 업데이트 API 요청
// 장바구니 수량 업데이트 API 요청
async function updateCartQuantity(itemId, quantity) {
try {
await axios.patch(
{ quantity },
{
headers: {
'Content-Type': 'application/json',
'client-id': 'vanilla01',
Authorization: `Bearer ${accessToken}`,
},
},
);
} catch (error) {
console.error(
'수량 업데이트에 실패했습니다:',
error.response ? error.response.data : error.message,
);
}
}
- 설명: 주어진 itemId에 대해 수량을 업데이트하는 API 요청을 보냅니다. 요청이 실패하면 에러 메시지를 콘솔에 출력합니다.
5. deleteCartItem(itemId): 장바구니에서 항목 삭제 API 요청
// 장바구니에서 항목 삭제 API 요청
async function deleteCartItem(itemId) {
try {
headers: {
'Content-Type': 'application/json',
'client-id': 'vanilla01',
Authorization: `Bearer ${accessToken}`,
},
});
} catch (error) {
console.error(
'항목 삭제에 실패했습니다:',
error.response ? error.response.data : error.message,
);
}
}
- 설명: 주어진 itemId에 해당하는 장바구니 항목을 삭제하는 API 요청을 보냅니다. 요청 실패 시 에러 메시지를 출력합니다.
6. DOMContentLoaded 이벤트 리스너: 페이지 로드 시 초기화 및 이벤트 설정
document.addEventListener('DOMContentLoaded', function () {
document
.getElementById('order-button')
.addEventListener('click', function () {
alert('주문이 완료되었습니다!');
});
initCart();
});
- 설명: 페이지가 로드될 때 호출되는 함수로, 주문 버튼에 클릭 이벤트를 추가하여 주문이 완료되었음을 알리는 알림을 표시합니다. 또한 initCart() 함수를 호출하여 장바구니를 초기화합니다.