ToyProject(더다주) cart(1)

노영완·2023년 7월 21일
0

ToyProject(더다주)

목록 보기
5/13

Cart 페이지를 만들어 Cart 기능을 넣기로 결정. CRUD의 기능이 다들어간 페이지라서 꼭 넣어야겠다고 생각한 페이지이며 가장 많이 막히고 힘들었던 페이지이기도 하다.

1. 장바구니 버튼 클릭시 장바구니 페이지에 내가 선택한 상품에 데이터가 나열되게끔.

2. 전체상품 주문 버튼 클릭시 전체상품을 주문해 장바구니에 모든 상품들이 마이페이지에 결제내역으로 넘어가게끔.

3. 선택상품 주문 버튼 클릭시 선택상품만 마이페이지 결제내역으로 넘어가게끔.

4. 선택한 상품만 삭제시키는 선택삭제 기능

5. 전체선택 클릭시 모든 상품에 아이콘이 클릭되게끔.

6. 수량이 변경이 되면 변경된 상품에 가격과 총 가격이 변동 되게끔.

7. x 아이콘 클릭시 상품하나가 삭제되게끔.

8. 장바구니에 상품들의 총 상품금액 총 결제금액이 계산되서 사용자에게 알져기 끔.

전체상품주문 기능

첫 생각

  1. 클라이언트쪽에서 처리보다는 서버쪽에서 처리가 훨씬 쉬울거라 판단
  2. 새로 Cart에서 코드를 짜는 거 보다는 기존 생성한 productOrder에서 해결하기로 생각
  3. 기존에 기능을 하고있는 productOrder와는 다르게 기능해야하니 query를 넘겨주어 차별성을 주자
  4. insertMany를 써 결제내역에 데이터를 추가하자 insertMany에 추가할 데이터는 find({})를 써 변수에 저장후 추가하자 차피 find로 찾은 데이터는 배열 모양일꺼니 가능할 것 이다.

클라이언트 코드

  const onClickEntireOrder = () => {
    if (window.confirm("전체상품을 주문하시겠습니까 ?") === true) {
      postMyOrderProduct("?type=전체상품주문", {
        _id: undefined,
        src: undefined,
        name: undefined,
        price: undefined,
        quantity: undefined,
        selectData: undefined,
      }).then((data) => {
        alert(data.message);
        if (window.confirm("주문내역을 확인하시겠습니까 ?") === true) {
          navigate("/mypage");
        } else {
          window.location.reload();
          window.scrollTo(0, 0);
        }
      });
    } else return;
  };

실제 클라이언트쪽 코드에서는 query만 전달해주었을뿐 body에 대한 데이터 값은 전달해주지 않았다.

서버 코드

myorderRouter.post("/", async (req, res) => {
  try {
    if (!req.user) throw new Error("권환이 없습니다.");
    const { type } = req.query;
    if (type === "전체상품주문") {
      const totalCart = await Cart.find({});
      const [totalDeleteCart, totalOrder] = await Promise.all([
        await Cart.deleteMany({}),
        await MyOrder.insertMany(totalCart),
      ]);
      return res.json({
        message: "전체상품의 주문이 완료되었습니다.",
      });
    }
  } catch (e) {
    res.status(400).json({ message: e.message });
  }
});

전체상품주문만 관련한 코드만 가져온 코드이다. query에 type이라는 키값에 "전체상품주문"이라는 value값이 들어오면 위에 코드가 실행 될 것이다. 일단 Cart에 데이터를 찾을 것이다. 실제 콘솔을 찍어보면 [data, data,data,data] data들은 배열에 담겨져 있는 것을 확인 할 수 있다. 배열에 담겨져있는 데이터들은 그대로 insertMany에 들어가 데이터가 생성될 것이다.
문제!
전체상품주문 기능을 다시 생각해보면 장바구니에 있는 상품들을 주문을 했고 주문을 했으면 결제내역에 올라가고 장바구니에 있는 상품들은 마이페이지로 넘어간다. 하지만 내가 처음으로 생각한 부분은 장바구니에 상품들이 그대로 남아있었다. 다른 방법이 있을거라 생각한다. Schema에서 충분히 핸들링 할 수 있지 않을까? 의심이 들지만 일단 학습의 목적이고 추후 해결할 문제로 놔두고 deleteMany()로 Cart에 데이터를 지우는 것으로 해결했다.

총 상품금액 총 결제금액

첫 생각

  1. 가격과 수량에 대한 값이 중요하다. 이 두가지 값은 map을 통해 읽어서 빼내야 할 것이다.
  2. map을 읽는 과정에서 가격과 수량을 곱해서 한번에 총 가격이 나오게끔 하자.
  3. 나온 총 가격은 배열에 넣어서 배열을 싹다 더해 값이 나오게끔 하자.
  const [totalArr, setTotalArr] = useState<number[]>([]);
  useEffect(() => {
    if (cartData.length === totalArr.length) return;
    cartData.map(({ price, quantity }) => {
      totalArr.push(price * quantity);
    });
  }, [cartData]);

cartData는 서버에서 가져온 데이터이며 map으로 읽고 각 데이터에서 가격과 수량을 가져와 곱한뒤 push를 이용해 배열 state인 totalArr에 넣었다.
이제는 더해야 했다. totalArr에는 정확하게 내가 원한대로 곱한 값이 들어갔다. 고민을 하다가 for를 통해 읽고 읽는 중간에 더하기로 생각했다. 근데 지금보니 그냥 map에서 읽을 때 더해도 충분했겠다는 생각이 들지만 if 조건문을 통해 에러를 잡은걸 생각해보면 그래도 배열을 만든거는 잘했다고 생각이 든다. 이 내용은 앞선 내용에서 설명할 것이다. 저 코드 한줄로 인해 두번 랜더링 되어 총 상품금액이 두배가 되는거를 막을수 있었다.

let totalPrice = 0;
  const totalPriceFunction = () => {
    for (let i = 0; i < totalArr.length; i++) {
      totalPrice += totalArr[i];
    }
    return totalPrice;
  };

수시로 변하는 값이니 상수가 아닌 let을 사용해 totalPrice에 기준이 되는 값을 잡고 for문을 통해 읽어 다 더해주었다.

수량변경 상품삭제(oneDelete)

첫 생각

  1. put patch 중에 patch를 사용하자 데이터 전체를 바꾸는 것보다는 수량하나만 바뀌는거기 때문에
  2. 수량이 0개 이상일때만 데이터는 변경될 수 있다.
  3. 사용자에게 수량이 변했다는 것을 바로바로 보여주어야 하기 때문에 수량의 데이터 값을 state로 관리 서버쪽에서 받아와서 관리하면 바로 보여주기 힘들다고 생각.

서버 코드

cartRouter.patch("/quantity", async (req, res) => {
  try {
    const { _id, quantity } = req.body;
    if (!mongoose.isValidObjectId(_id)) throw new Error("유효하지 않은 아이디");
    if (typeof quantity !== "number") throw new Error("숫자 타입이 아닙니다.");
    if (quantity === 0) throw new Error("수량은 0개 이상입니다.");
    const cartQuantity = await Cart.findByIdAndUpdate(
      { _id },
      { quantity },
      { new: true }
    );
    return res.json({ cartQuantity });
  } catch (e) {
    res.status(400).json({ message: e.message });
  }
});

id 값을 전달해주어 맞는 상품의 유무를 확인 findByIdUpdate로 데이터 변경 불리언타입인지 확인 수량이 0개 이상일때만 코드 실행되게끔.

클라이언트 코드

  const [quantityData, setQuantityData] = useState(quantity);
  const plustQuantity = () => {
    setQuantityData(quantityData + 1);
    patchCartQuantity(_id, quantity + 1);
    window.location.reload();
  };
  const minusQuantity = () => {
    if (quantity === 1) return alert("더 이상 수량을 줄일 수 없습니다.");
    setQuantityData(quantityData - 1);
    patchCartQuantity(_id, quantity - 1);
    window.location.reload();
  };

변한 데이터의 값을 바로 보여주어야 하기 때문에 state로 관리 patch 통신을 하였고 cartData의 값을 변경해주면 장바구니 페이지에 값이 바뀔거라 생각했지만 총 결제금액은 바뀌지 않음. 분명히 cartData가 변경되면 변하게끔 코드를 짰지만 변경하지 않아 플러스 마이너스 클릭시 리다이렉트 하게끔 코드 구현.

findOneAndDelete를 통해 삭제하게끔 구현. 클라이어트측에서는 id값만 서버에 보내 서버에서 id에 값을 찾아 삭제하게끔

0개의 댓글