Developer/PROJECT.React

리액트 프로젝트 6. 구매 금액수량변경 , 장바구니 불러오기

단님 2024. 7. 2. 12:22
728x90
ProductBuy [/goods/:category/:id/buy]

 

단품 구매를 위한 페이지를 제작하게 되었다.

form 에서 구매하기 버튼을 누르면 이컴포넌트가 실행되는데

팀원들의 니즈는 단품에 대한 수량변경이 여기서도 가능했으면 좋겠다. 라는 점이였다.

form에서 한거 들고오면되지...

laction을 통해 state로 가지고 온값을 일치시켜서 먼저 초기값으로 넣어주는 작업을 하였다.

 

    const location = useLocation();
    const { category, id } = useParams();
    const { options, btnValue, totalPrice } = location.state || {};

 

options가 옵션에 대한 내용,

btnValue가 선택된 값,

totalPrice 가 이 옵션과 선택된 값을 계산한 결과였다.

이 정보로는 선택 상품에 대한 값을 찾을 수 없기 때문에 usePrams 를 통해 선택된 아이템 을 찾을 수 있었다.

  const [buyPrice, setBuyPrice] = useState({
        productPrice: btnValue ? btnValue.contentSelect : 1,
        optionPrice: btnValue ? btnValue.packagingSelect : 1,
    });

혹시 값을 찾지 못할수도 있을것 같아 방어코드도 함께 넣어주었다.

값을 다시 재계산을 이루어야 하기때문에

계산하는 함수를 사용하여 선택된 아이템 값에 맞는 계산을 이루어야 한다.

    //최종 금액을 바꿀 state (배송비 제외)
    const [filterPrice, setFilterPrice] = useState(+totalPrice);
    //배송비 추가금을 포함한 최종금액 표현.
    const [lastPrice, setLastPrice] = useState(+filterPrice);

 

가장 어려웠던 부분은 3만원 미만은 배송비가 붙는 점이였는데,

그 부분을 UI에 함께 표현하고싶어서 다른 state를 이용하게 되었다.

totalPrice = (price + contentPrice) * buyPrice.productPrice + packagingPrice * buyPrice.optionPrice;

 

UI는 이런식으로 표현하게 되었다.

{showingMessage && lastPrice > 0 && <span>(배송비 추가 발생 되었습니다.)</span>}
{lastPrice <= 0 && <span>(구매 하실 수 없습니다)</span>}

 

처음에는 filterPrice가 3만원 미만일때의 조건으로 배송비 추가 메세지를 할 수 있었는데 

showingMessage 를 이용하게 된 이유는 바로..

 

장바구니를 불러오는 로직을 추가로 만들게 되었기 때문이다.

(욕망덩어리 또시작이야..)

 

 

filter는 버튼 클릭했을때만 변하고 , 

장바구니를 불러와 펼쳐놓은 다음

장바구니 내역이 체크되었을때 그 값들을 더해서 구매 완료시에 전송해줘야한다.

 

하필 나는 장바구니 불러오는 내역을 하위컴포넌트로 따로 빼두었는데 .

하위에서 상위로 상태값을 전송해줘야했다..

 

하위의 장바구니 체크박스를 어떤 고객이던 어떤 수량이던 유동적으로 생성되어야 하기때문에

state의 초기값으로 map을 돌리게 되었다.

배열형식으로 반환되기 때문에

배열형식으로 checked 값을 변경해주면 된다.

 

 

ProductBuy - BuyBasketList

1. state

// 각 장바구니 항목의 체크 상태를 관리하는 배열
const [checkedItems, setCheckedItems] = useState(
    userCart.map(() => false)
);

 

2. map 안에서 펼쳐지는 input

<input type="checkBox"
    checked={checkedItems[index]}
    value={cartItem.totalPrice}
    onChange={(e) => onChangeCheckBox(index, e)}/>

 

3. onChange 이벤트

// 체크박스 상태 변경 함수
const onChangeCheckBox = (index, event) => {
    const isChecked = (event.target.checked);

    const item = userCart[index];


    // 해당 인덱스의 체크 상태를 업데이트
    setCheckedItems((it)=>{
        const copyIschecked = [...it];
        copyIschecked[index] = isChecked;
        return copyIschecked;
    });

    // 상위 컴포넌트에 상태 변경 알림
    onChangeChildCheckbox(isChecked ,item);
};

isChecked 가 현재 체크된 상태를 

카피한 state 배열을 넣어주는 형태다.

 

그리고 현재 상태를 상위로 올려준다.

ProductBuy

하위에서 받은 정보로 상위컴포넌트의 상태값을 변경.

 

//장바구니 항목 체크 박스에 대해 정보를 저장할 배열 변수.
    const [checkedCartItems, SetCheckedCartItems] = useState([]);
    // 장바구니 항목 체크박스 상태 변경 함수 // 하위컴포넌트로 프롭스로 전달.
    const onChangeChildCheckbox = (isChecked, items) => {


        //체크된 항목을 하위 컴포넌트로 전송하기 위한 배열 형성.
        SetCheckedCartItems(prevItems => {
            if (isChecked) {
                return [...prevItems, items]
            } else {
                return prevItems.filter(cartItem => cartItem.productId !== items.productId);
            }

        });
        console.log(checkedCartItems)
    };

 

 

장바구니 토탈 금액에 대한 정보는 합산하는 배열의 reduce 메서드를 이용했다.

const cartTotalPrice = checkedCartItems.reduce((acc, item) => acc + item.totalPrice, 0);

 

하지만 selectProduct이 선택이 됬다면 단품 가격도 포함되어야 하기 때문에

단품 체크에 대한 상태값이 true 일때

const combinedPrice = (buyCheckBox ? filterPrice : 0) + cartTotalPrice;

 

마지막 최종금액이 담긴 combinedPrice를 통해 마지막 LastPrice를 표현할 수 있었다.

    if (combinedPrice === 0) {
        setLastPrice(0);
        setShowingMessage(false);
    } else if (combinedPrice < 30000) {
        setLastPrice(combinedPrice + 3000);
        setShowingMessage(true);
    } else {
        setLastPrice(combinedPrice);
        setShowingMessage(false);
    }

0원이면

배송비 문구는 지우고 , 결제 불가의 메세지(lastPrice 0 일때 나옴.)만 표현 가능.

30000원 미만일때 ,

배송비 문구를 보여주면서 3000원 추가

3만원 이상일때는 배송비 문구 지우고 토탈금액만 표시.

 

이 계산은 useEffect를 통해 

옵션이 바뀌었을때 ,  체크되어 checkedCartItems가 늘어날때 , fiterPrice가 변경될때 지정해주었고,

 

장바구니 불러오기 클릭시에

CheckedCartItems 를 초기화 해주었고

LastPrice를 filterPrice가 들어갈 수 있도록 조정해주었다.

 

 

필요한 항목들을 input 컴포넌트의 구매하기 를 눌렀을때 전송되야 하기때문에 하위컴포넌트로 

프롭스를 왕창 던저주었다......ㅎ

 

<BuyInputBox
    userData={userData}
    buyPrice={buyPrice}
    checkedCartItems={checkedCartItems}
    options={options}
    selectedProduct={buyCheckBox && selectedProduct}
    productPrice={filterPrice}
    totalPrice={lastPrice} />