장바구니 추가기능

강현구·2022년 1월 17일

Node.js

목록 보기
17/19

이번엔 장바구니 추가 기능을 한번 해보겠다.
먼저 장바구니 데이터를 데이터베이스에 담기 위해 스키마를 만든다.
schemas폴더에 basket.js 파일을 만든다.

const mongoose = require("mongoose");

const { Schema } = mongoose;
const basketSchema = new Schema({
  productId: {
    type: Number,
    required: true,
    unique: true
  },
  quantity: {
    type: Number,
    required: true
  }
});

module.exports = mongoose.model("Basket", basketSchema);

이렇게 코드를 작성한다. 장바구니 스키마에는 productId와 quantity 두개를 넣었다.
productId만 있으면 상품의 정보를 다 찾을수 있고, 수량을 알기 위해 quantity를 넣었다.
이제 routers/products.js에 api도 추가한다.

const Basket = require("../schemas/basket");

router.post("/products/:productId/basket", async (req, res) => {
  const { productId } = req.params;
  const { quantity } = req.body;

  isBasket = await Basket.find({ productId });
  console.log(isBasket, quantity);
  if (isBasket.length) {
    await Basket.updateOne({ productId }, { $set: { quantity } });
  } else {
    await Basket.create({ productId: productId, quantity: quantity });
  }
  res.send({ result: "success" });
});

이렇게 데이터베이스에 업로드 하는 api를 추가한다.
이제 서버를 실행해보고 제품 상세 화면에서 장바구니를 누르면 데이터베이스에 저장이 될 것이다.
이제 저장된 장바구니를 보기위해 템플릿을 만들어 보도록 하자.
templates폴더안에 basket.ejs를 만들어 준다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
    <link rel="icon" href="/static/favicon.ico" type="image/x-icon" />
    <link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon" />
    <!-- Bootstrap CSS -->
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"
      integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
      crossorigin="anonymous"
    />

    <!-- Font Awesome CSS -->
    <link
      href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
      rel="stylesheet"
    />
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script
      src="https://code.jquery.com/jquery-3.5.1.js"
      integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
      crossorigin="anonymous"
    ></script>
    <script
      src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"
      integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN"
      crossorigin="anonymous"
    ></script>
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js"
      integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s"
      crossorigin="anonymous"
    ></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>

    <link href="/static/mystyle.css" rel="stylesheet" />
    <title>스파르타 쇼핑몰 | 장바구니</title>
    <script>
      $(document).ready(function() {
        get_goods();
        $("#categorySelect").on("change", function() {
          get_goods($(this).val());
        });
      });

      function sign_out() {
        $.removeCookie("mytoken", { path: "/" });
        $.removeCookie("userName", { path: "/" });
        window.location.href = "/";
      }

      function get_goods() {
        $("#productsList").empty();
        $.ajax({
          type: "GET",
          url: `/api/basket`,
          data: {},
          success: function(response) {
            let products = response["basket"];
            console.log(products);
            for (let i = 0; i < products.length; i++) {
              make_card(products[i]["products"], products[i]["quantity"]);
            }
            getSum();
          }
        });
      }

      function order() {
        $.ajax({
          type: "GET",
          url: `/api/basket`,
          data: {},
          success: function(response) {
            let products = response["basket"];
            let basket = [];
            for (let i = 0; i < products.length; i++) {
              basket.push({
                productsName: products[i]["name"],
                quantity: products[i]["productId"]
              });
            }
            sessionStorage.setItem("basket", JSON.stringify(basket));
            window.location.href = "/order";
          }
        });
      }

      function make_card(item, quantity) {
        let htmlTemp = `<div class="card mb-2">
                                    <div class="row no-gutters">
                                        <div class="col-4" style="background: #868e96;"token interpolation">${
                                          item["productId"]
                                        }'">
                                            <img src="${item["imageUrl"]}"
                                                 class="card-img-top h-100" alt="...">
                                        </div>
                                        <div class="col-8">
                                            <div class="card-body py-1">
                                                <div class="card-title row mt-2">
                                                    <p class="font-weight-bold col" style="display: inline">${
                                                      item["name"]
                                                    }</p>
                                                    <span class="card-price col text-right">$${number2decimals(
                                                      item["price"]
                                                    )}</span>

                                                </div>
                                                <div class="form-group row mr-0">
                                                    <div class="col-7 pr-2">
                                                        <button class="btn btn-outline-sparta btn-block"token interpolation">${
                                                          item["productId"]
                                                        })">삭제</button>
                                                    </div>
                                                    <select class="custom-select col-5" id="numberSelect-${
                                                      item.productId
                                                    }">
                                                      ${[1, 2, 3, 4, 5]
                                                        .map(
                                                            (i) =>
                                                            `<option ${
                                                                i === quantity ? "selected" : ""
                                                            } value="${i}">${i}</option>`
                                                        )
                                                        .join(" ")}
                                                    </select>
                                                </div>

                                            </div>


                                        </div>
                                    </div>
                                </div>`;
        $("#productsList").append(htmlTemp);
        $(`#numberSelect-${item["productId"]}`).change(function() {
          // console.log(parseInt($(this).val()))
          $.ajax({
            type: "PATCH",
            url: `/api/products/${item["productId"]}/basket`,
            data: {
              quantity: parseInt($(this).val())
            },
            success: function(response) {
              if (response["result"] == "success") {
                console.log(response["msg"]);
                getSum();
              }
            }
          });
        });
      }

      function removeItem(productId) {
        $.ajax({
          type: "DELETE",
          url: `/api/products/${productId}/basket`,
          data: {},
          success: function(response) {
            if (response["result"] == "success") {
              get_goods();
            }
          }
        });
      }

      function getSum() {
        let $prices = $(".card-price");
        let $selects = $("select");
        if ($prices.length != $selects.length) {
          console.log("길이가 맞지 않습니다.");
          return;
        }
        let sum = 0;
        for (let i = 0; i < $prices.length; i++) {
          let price = parseFloat(
            $($prices[i])
              .text()
              .replace("$", "")
          );
          let count = parseInt($($selects[i]).val());
          // console.log(price, count)
          sum += price * count;
        }
        $("#priceSum").text("$" + number2decimals(sum));
        sessionStorage.setItem("priceSum", number2decimals(sum));
      }

      function number2decimals(num) {
        return (Math.round(num * 100) / 100).toFixed(2);
      }
    </script>
    <style>
      .card {
        cursor: pointer;
      }
    </style>
  </head>

  <body>
    <nav
      class="navbar navbar-expand-sm navbar-dark bg-sparta justify-content-end"
    >
      <a class="navbar-brand" href="/home">
        <img
          src="/static/logo_big_tr.png"
          width="30"
          height="30"
          class="d-inline-block align-top"
          alt=""
        />
        스파르타 쇼핑몰
      </a>
      <button
        class="navbar-toggler ml-auto"
        type="button"
        data-toggle="collapse"
        data-target="#navbarSupportedContent"
        aria-controls="navbarSupportedContent"
        aria-expanded="true"
        aria-label="Toggle navigation"
      >
        <span class="navbar-toggler-icon"></span>
      </button>
      <div
        class="navbar-collapse collapse flex-grow-0 ml-auto"
        id="navbarSupportedContent"
        style=""
      >
        <ul class="navbar-nav mr-auto text-right">
          <li class="nav-item" id="link-cart">
            <a class="nav-link" href="/basket">
              장바구니<i
                class="fa fa-shopping-cart ml-2"
                aria-hidden="true"
              ></i>
            </a>
          </li>
          <li class="nav-item" id="link-logout">
            <a class="nav-link" data-toggle="modal" data-target="#signOutModal">
              로그아웃<i class="fa fa-sign-out ml-2" aria-hidden="true"></i>
            </a>
            <div
              class="modal text-left"
              id="signOutModal"
              tabindex="-1"
              role="dialog"
              aria-labelledby="signOutModalLabel"
              aria-hidden="true"
            >
              <div class="modal-dialog" role="document">
                <div class="modal-content">
                  <div class="modal-header">
                    <h5 class="modal-title" id="signOutModalLabel">로그아웃</h5>
                    <button
                      type="button"
                      class="close"
                      data-dismiss="modal"
                      aria-label="Close"
                    >
                      <span aria-hidden="true">&times;</span>
                    </button>
                  </div>
                  <div class="modal-body">
                    로그아웃하시면 장바구니가 사라져요!
                  </div>
                  <div class="modal-footer">
                    <button
                      type="button"
                      class="btn btn-outline-sparta"
                      data-dismiss="modal"
                    >
                      취소
                    </button>
                    <button
                      type="button"
                      class="btn btn-sparta"
                      onclick="sign_out()"
                    >
                      로그아웃하기
                    </button>
                  </div>
                </div>
              </div>
            </div>
          </li>
        </ul>
      </div>
    </nav>
    <div class="wrap">
      <div class="mb-3">
        <h4>
          <i class="fa fa-shopping-cart mr-1" aria-hidden="true"></i>장바구니
        </h4>
      </div>
      <div id="productsList">
        <div class="card mb-2" onclick="location.href='#'">
          <div class="row no-gutters">
            <div class="col-4" style="background: #868e96;">
              <img
                src="https://cdn.pixabay.com/photo/2016/09/07/19/54/wines-1652455_1280.jpg"
                class="card-img-top h-100"
                alt="..."
              />
            </div>
            <div class="col-8">
              <div class="card-body py-1">
                <div class="card-title row mt-2">
                  <p class="font-weight-bold col" style="display: inline">
                    상품 1
                  </p>
                  <span class="card-price col text-right">$6.20</span>
                </div>
                <div class="form-group row mr-0">
                  <div class="col-7 pr-2">
                    <button class="btn btn-outline-sparta btn-block">
                      삭제
                    </button>
                  </div>
                  <!--                                    <label for="numberSelect" class="col col-form-label">수량</label>-->
                  <select class="custom-select col-5" id="numberSelect">
                    <option selected value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                  </select>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <hr />

      <div class="row mb-3">
        <div class="col-5">총 상품금액</div>
        <div class="col-7 text-right" id="priceSum">$6.20</div>
      </div>
      <button type="button" class="btn btn-sparta btn-block" onclick="order()">
        구매
      </button>
    </div>
  </body>
</html>

이렇게 장바구니 템플릿을 만들어 준다.
템플릿을 만들어 주었으니 index.js 파일에 루트를 추가해 준다.

app.get("/basket", (req, res) => {
  res.render("basket");
});

이렇게 추가를 해주고 이제 다시 제품 상세페이지 에서 장바구니에 담고 장바구니로 이동을 눌러주면 장바구니 페이지로 들어가게 된다.
이제 그 장바구니 페이지에 데이터베이스에서 가져온 정보를 넣어야 하니 데이터베이스에서 정보를 가져오는 api를 만들어 보자.

router.get("/basket", async (req, res) => {
  const basket = await Basket.find({});
  const productId = basket.map(basket => basket.productId);

  productsInCart = await Products.find()
    .where("productId")
    .in(productId);


  concatCart = basket.map(c => {
    for (let i = 0; i < productsInCart.length; i++) {
      if (productsInCart[i].productId == c.productId) {
        console.log(c.quantity, productsInCart[i]);
        return { quantity: c.quantity, products: productsInCart[i] };
      }
    }
  });

  res.json({
    basket: concatCart
  });
});

이렇게 장바구니를 가져오는 api를 추가한다.
이 코드는 데이터베이스의 장바구니에서 데이터를 가져와서 productId만 다시 가져와서 저장해준다.
그리고 productId를 이용해 Products 데이터베이스에서 맞는 상품들을 가져온다.
그리고 concatCart에 for문을 이용해서 카트에 담겨있는 만큼 반복을 해주고, 만약 카트에 담겨있는 물건과 장바구니의 물건의 아이디가 같다면 수량과 상품정보를 리턴시켜준다.
그리고 res.json으로 basket아란 이름으로 concatCart를 보내준다.

router.delete("/products/:productId/basket", async (req, res) => {
  const { productId } = req.params;

  const isProductsInBasket = await Basket.find({ productId });
  if (isProductsInBasket.length > 0) {
    await Basket.deleteOne({ productId });
  }

  res.send({ result: "success" });
});

이 코드를 routers/products.js에 추가해 준다.
데이터베이스에서 상품을 지우는 코드이다.
productId값을 받아와서 그 아이디 값을 데이터베이스에서 찾아준다.
그 아이디값이 있다면, 그 아이디 값을 가진 데이터를 지워준다.
이제 서버를 실행해서 장바구니에 아이템을 지우면 잘 지워지는것을 확인 할 수 있다.
다음은 장바구니 수량을 정정해보자.

router.patch("/products/:productId/basket", async (req, res) => {
  const { productId } = req.params;
  const { quantity } = req.body;

  isBasket = await Basket.find({ productId });
  console.log(isBasket, quantity);
  if (isBasket.length) {
    await Basket.updateOne({ productId }, { $set: { quantity } });
  }

  res.send({ result: "success" });
})

이 코드를 마찬가지로 routers/products.js에 추가해준다.
이 코드는 productId를 받아오고, quantity값을 일단 받아온다. 그리고 productId값으로 데이터베이스에서 상품을 찾는다.
그리고 그 상품이 있을 경우 그 상품의 quantity값을 방금 받아온 quantity값으로 다시 지정해준다.
이제 서버를 실행해서 장바구니에서 수량을 바꾸면 잘 바뀌는것을 확인 할 수 있다.
이렇게 장바구니 파트를 끝마친다.

profile
초보개발자

0개의 댓글