장바구니 페이지 스크립트

1. 주문 버튼 검증

document.addEventListener("DOMContentLoaded", function () {

    // 주문 버튼 클릭 시 체크된 상품 없으면 경고
    const orderForm = document.getElementById('order-form');
    const orderButton = document.getElementById('order-button');

    orderButton.addEventListener('click', function (e) {
        const checkedItems = orderForm.querySelectorAll('input[name="cartNo"]:checked');

        if (checkedItems.length === 0) {
            e.preventDefault(); // 폼 제출 막기
            alert('주문할 상품을 선택해주세요.');
        }
    });
    // … 이하 생략
});

기능 설명

2. 요약 정보 업데이트 함수

    // 수량 +, - 버튼 및 체크박스들
    const plusBtns = document.querySelectorAll('.btn-plus');
    const minusBtns = document.querySelectorAll('.btn-minus');
    const checkAll = document.querySelector('#check-all');
    const itemCheckboxes = document.querySelectorAll('.cart_content input[type="checkbox"]');

    // 요약 정보 업데이트 함수
    function updateSummary() {
        let totalCount = 0;
        let originalTotalAmount = 0;
        let discountTotal = 0;
        let actualPayAmount = 0;
        const uniqueVendors = new Set();

        const deliveryFeePerVendor = 2500;
        const freeShippingLimit = 1000000;

        // 체크된 각 상품에 대해 계산
        itemCheckboxes.forEach((cb) => {
            if (cb.checked) {
                const cartContent = cb.closest('.cart_content');
                const quantity = parseInt(cartContent.querySelector('.quantity').textContent);

                const priceOriginalEl = cartContent.querySelector('.price_original');
                const priceTotalEl = cartContent.querySelector('.price_total');

                const unitOriginal = parseInt(priceOriginalEl.dataset.unit);
                const unitTotal = parseInt(priceTotalEl.dataset.unit);

                const itemDiscount = (unitOriginal - unitTotal) * quantity;
                const itemOriginalPrice = unitOriginal * quantity;
                const itemTotalPrice = unitTotal * quantity;

                const vendorNameEl = cartContent.querySelector('.vendor-name');
                if (vendorNameEl) {
                    uniqueVendors.add(vendorNameEl.textContent.trim());
                }

                totalCount += quantity;
                originalTotalAmount += itemOriginalPrice;
                discountTotal += itemDiscount;
                actualPayAmount += itemTotalPrice;
            }
        });

        const orderAmount = originalTotalAmount - discountTotal;

        // 판매자별 최대 배송비 계산
        const vendorDeliveryMap = new Map();

        itemCheckboxes.forEach((cb) => {
            if (cb.checked) {
                const cartContent = cb.closest('.cart_content');
                const deliveryFeeEl = cartContent.querySelector('.price_delivery');
                const vendorNameEl = cartContent.querySelector('.vendor-name');
                const vendor = vendorNameEl ? vendorNameEl.textContent.trim() : '';

                const rawDeliveryFee = deliveryFeeEl?.dataset.deliveryFee;
                const deliveryFee = parseInt(rawDeliveryFee || '0');

                if (vendor) {
                    const currentMax = vendorDeliveryMap.get(vendor) || 0;
                    if (!isNaN(deliveryFee)) {
                        vendorDeliveryMap.set(vendor, Math.max(currentMax, deliveryFee));
                    } else {
                        vendorDeliveryMap.set(vendor, Math.max(currentMax, 0));
                    }
                }
            }
        });

        // 배송비 최종 합계
        let shippingCost = 0;
        vendorDeliveryMap.forEach((fee) => {
            if (fee > 0) {
                shippingCost += deliveryFeePerVendor;
            }
        });
        if (totalCount === 0 || orderAmount >= freeShippingLimit) {
            shippingCost = 0;
        }
        const finalTotal = orderAmount + shippingCost;
        const shippingText =
            totalCount === 0 ? '0'
                : orderAmount >= freeShippingLimit ? '무료'
                    : shippingCost.toLocaleString() + '원';

        // 요약 DOM 업데이트
        document.getElementById('summary-count').textContent = totalCount;
        const checkAllLabel = document.querySelector('label[for="check-all"]');
        if (checkAllLabel) {
            checkAllLabel.textContent = `전체선택(${totalCount})`;
        }

        document.getElementById('summary-amount').textContent = originalTotalAmount.toLocaleString();
        document.getElementById('summary-discount').textContent = '-' + discountTotal.toLocaleString();
        document.getElementById('summary-shipping').textContent = shippingText;
        document.getElementById('summary-total').textContent = finalTotal.toLocaleString() + '원';
    }

기능 설명

  1. 체크된 상품을 순회하면서
    • 수량(.quantity), 원가 단가(.price_original.dataset.unit), 할인 단가(.price_total.dataset.unit)를 파싱
    • itemDiscount = (원가 단가 − 할인 단가) × 수량
    • itemOriginalPrice = 원가 단가 × 수량
    • itemTotalPrice = 할인 단가 × 수량
    • 각 값을 누적하여
      • totalCount(총 수량)
      • originalTotalAmount(상품 원가 합계)
      • discountTotal(총 할인 금액)
      • actualPayAmount(총 결제 금액, 실제로는 사용되지 않지만 계산해 둠)
    • uniqueVendors에 판매자명 추가(배송비 계산 시 중복 방지용)
  2. orderAmount = originalTotalAmount − discountTotal
  3. 판매자별 최대 배송비(vendorDeliveryMap) 계산
    • 각 체크된 상품의 data-delivery-fee 값을 파싱
    • 판매자별로 최대 배송비만 보관(Math.max)
  4. 최종 배송비(shippingCost) 계산
    • 배송비가 0보다 큰 판매자마다 deliveryFeePerVendor(2,500원) 추가
    • 주문 수량이 0이거나 orderAmount ≥ freeShippingLimit(1,000,000원)인 경우 배송비 0 처리
  5. finalTotal = orderAmount + shippingCost
  6. 텍스트로 표시할 shippingText
    • totalCount === 0 → '0'
    • orderAmount ≥ freeShippingLimit → '무료'
    • 그 외 → shippingCost를 천 단위 콤마로 표시 후 '원' 붙임
  7. 다음 DOM 요소들에 값 할당
    • #summary-count ← totalCount
    • label[for="check-all"] ← 전체선택(totalCount)
    • #summary-amount ← originalTotalAmount(천 단위 콤마)
    • #summary-discount ← "-discountTotal"(천 단위 콤마)
    • #summary-shipping ← shippingText
    • #summary-total ← finalTotal원(천 단위 콤마 + '원')

3. 수량 조절 기능

    // 수량 조절 버튼
    plusBtns.forEach((btn) => {
        btn.addEventListener('click', () => {
            const cartContent = btn.closest('.cart_content');
            const quantityEl = cartContent.querySelector('.quantity');
            let count = parseInt(quantityEl.textContent);
            count++;
            quantityEl.textContent = count;

            const priceOriginalEl = cartContent.querySelector('.price_original');
            const priceTotalEl = cartContent.querySelector('.price_total');
            const unitOriginal = parseInt(priceOriginalEl.dataset.unit);
            const unitTotal = parseInt(priceTotalEl.dataset.unit);

            priceOriginalEl.textContent = (unitOriginal * count).toLocaleString() + '원';
            priceTotalEl.textContent = (unitTotal * count).toLocaleString() + '원';

            const cartNoInput = cartContent.querySelector('input[name="cartNo"]');
            const cartNoValue = cartNoInput.value;

            updateCartProductCount(cartNoValue, count);

            updateSummary();
        });
    });

    minusBtns.forEach((btn) => {
        btn.addEventListener('click', () => {
            const cartContent = btn.closest('.cart_content');
            const quantityEl = cartContent.querySelector('.quantity');
            let count = parseInt(quantityEl.textContent);
            if (count > 1) {
                count--;
                quantityEl.textContent = count;

                const priceOriginalEl = cartContent.querySelector('.price_original');
                const priceTotalEl = cartContent.querySelector('.price_total');
                const unitOriginal = parseInt(priceOriginalEl.dataset.unit);
                const unitTotal = parseInt(priceTotalEl.dataset.unit);

                priceOriginalEl.textContent = (unitOriginal * count).toLocaleString() + '원';
                priceTotalEl.textContent = (unitTotal * count).toLocaleString() + '원';

                const cartNoInput = cartContent.querySelector('input[name="cartNo"]');
                const cartNoValue = cartNoInput.value;

                updateCartProductCount(cartNoValue, count);

                updateSummary();
            }
        });
    });

기능 설명

4. 수량 변경 서버 업데이트

    // 수량 변경 업데이트
    function updateCartProductCount(cartNo, newQuantity) {
        const formData = new URLSearchParams();
        formData.append("cartNo", cartNo);
        formData.append("newQuantity", newQuantity);

        fetch('/update/cartProdCount', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: formData.toString()
        })
            .then(response => response.json())
            .then(data => {
                console.log('Cart updated:', data);
            })
            .catch(error => {
                console.error('Error updating cart:', error);
            });
    }

기능 설명

5. 체크박스 및 전체선택 기능

    // 체크박스 변화 시 요약 업데이트
    itemCheckboxes.forEach(cb => cb.addEventListener('change', updateSummary));

    // 전체 선택 기능
    checkAll.addEventListener('change', function () {
        const isChecked = this.checked;
        itemCheckboxes.forEach(cb => cb.checked = isChecked);
        updateSummary();
    });

기능 설명

6. 초기화 및 요약 초기 계산

    // 초기화 시 전체 해제 및 요약 초기 계산
    itemCheckboxes.forEach(cb => cb.checked = false);
    updateSummary();

기능 설명

7. 판매자별 상품 정렬 기능