코딩하는 김딸기

카트 js 본문

카테고리 없음

카트 js

김딸기* 2024. 10. 31. 03:35

이 코드는 장바구니와 위시리스트 기능을 구현하는 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) {
      // 로그인한 경우
      response = await axios.get('https://11.fesp.shop/carts', {
        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 =
          item.product.image.path || 'https://via.placeholder.com/150';
        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 =
        item.product?.image?.url || 'https://via.placeholder.com/150';
      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(
      `https://11.fesp.shop/carts/${itemId}`,
      { 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 {
    await axios.delete(`https://11.fesp.shop/carts/${itemId}`, {
      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() 함수를 호출하여 장바구니를 초기화합니다.