๐Ÿฉบ๐Ÿช Dr.Tart - Retrospect (2)

sanha_OvOยท2021๋…„ 12์›” 19์ผ
1

Project

๋ชฉ๋ก ๋ณด๊ธฐ
3/7

์ „๋ฐ˜์ ์ธ ๊ฐœ์š”๋ฅผ ์ž‘์„ฑํ–ˆ์œผ๋‹ˆ...

์ด์ œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ ์–ด๋ ค์› ๋˜ ์ ์„ ๋‚จ๊ฒจ๋ณผ๊นŒ ํ•œ๋‹ค.


์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ†ตํ•œ Order ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ

ํด๋ก ํ•  ๊ธฐ์กด์˜ ์‚ฌ์ดํŠธ์˜ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์™€ ๊ฒฐ์ œ ํŽ˜์ด์ง€์˜ ๋ ˆ์ด์•„์›ƒ์ด ๋˜‘ ๋‹ฎ์•˜๋‹ค.

๊ฐ™์€ ๋ ˆ์ด์•„์›ƒ ๊ฐ™์€ CSS๋ฅผ ์œ„ํ•ด ํŒŒ์ผ์„ ๋‘๊ฐœ์”ฉ ๋” ๋งŒ๋“ค๊ณ  ํ•˜๋Š” ๊ฒƒ์ด ๊ต‰์žฅํžˆ ๋น„ํšจ์œจ์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์—ฌ,

๊ฐ™์€ ํŽ˜์ด์ง€ ๋‚ด์—์„œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ†ตํ•ด ํšจ์œจ์ ์ธ ๊ตฌ์„ฑ์„ ๋ชฉํ‘œ๋กœ ์ฝ”๋”ฉ์„ ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

๊ทธ๋Ÿผ ์–ด๋–ค ์‹์œผ๋กœ ์ฝ”๋”ฉ ํ• ๊ฑด๋ฐ?

react-router์˜ useParams ํ›…์„ ์ด์šฉํ•˜์—ฌ cart ํŽ˜์ด์ง€์™€ checkout ํŽ˜์ด์ง€๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๊ณ ,

๊ทธ์— ๋”ฐ๋ผ ์กฐ๊ฑด๋ถ€๋กœ ๋ทฐ๋ฅผ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์˜€๋‹ค.

Order.js

import React, { useCallback, useEffect, useState } from 'react';
import { Link, useLocation, useParams, useNavigate } from 'react-router-dom';
import Button from '../../components/Button/Button';
import Goods from './Goods/Goods';
import { API_ADDRESS } from '../../apiConfig';
import './Order.scss';

const Order = () => {
  const [cartList, setCartList] = useState([]);
  const { pageType } = useParams();

  // ...
  
  useEffect(() => {
    if (pageType === 'cart') {
      (async () => {
        setIsOrderLoading(true);
        await fetchCartData();
        setIsOrderLoading(false);
      })();
    } else {
      setCartList(() => location.state.cartList);
      setTotalPrice(() => 0);
      location.state.cartList.forEach(({ price, quantity }) => {
        setTotalPrice(prev => prev + price * quantity);
      });
    }
  }, [fetchCartData, pageType, location]);

  // ...

  return (
    <div className="order">
      <div className="pageTitleArea">
        <div className="progressNav">
          <ul className="progress">
            <li className="stepOne">
              <p>01 ์žฅ๋ฐ”๊ตฌ๋‹ˆ</p>
              {pageType === 'cart' && <span className="line" />}
            </li>
            <li className="stepTwo">
              <p>02 ๊ฒฐ์ œ์ง„ํ–‰</p>
              {pageType === 'check' && <span className="line" />}
            </li>
            <li className="stepThree">
              <p>03 ์ฃผ๋ฌธ์™„๋ฃŒ</p>
            </li>
          </ul>
        </div>
        <div className="pageTitle">
          <h1 className="orderTitle">
            {pageType === 'cart' && '์žฅ๋ฐ”๊ตฌ๋‹ˆ'}
            {pageType === 'check' && '๊ฒฐ์ œ์ง„ํ–‰'}
          </h1>
        </div>
      </div>
      <div className="pageContent">
        
        {// ...}
          
        <div className="orderTotal">
          {pageType !== 'cart' && (
            <div className="orderInfoContainer">
              <div className="selectBox">
                <button className="selectedValue">์‹ ์šฉ์นด๋“œ</button>
                <ul className="valueList">
                  <li>์‹ ์šฉ์นด๋“œ</li>
                  <li>์นด์นด์˜คํŽ˜์ด</li>
                  <li>๋„ค์ด๋ฒ„ํŽ˜์ด</li>
                  <li>ํœด๋Œ€ํฐ๊ฒฐ์ œ</li>
                  <li>ํฌ์ธํŠธ</li>
                </ul>
              </div>
              <div className="mustCheck">
                <input
                  className="checkBox"
                  type="checkbox"
                  value={isTermsChecked}
                  onChange={() => setIsTermsChecked(prev => !prev)}
                />
                <label className="label" htmlFor="agree">
                  ๊ตฌ๋งคํ•˜์‹ค ์ƒํ’ˆ์˜ ํŒ๋งค์กฐ๊ฑด์„ ๋ช…ํ™•ํžˆ ํ™•์ธํ•˜์˜€์œผ๋ฉฐ, ์ด์—
                  ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.
                  <br />
                  (์ „์ž์ƒ๊ฑฐ๋ž˜๋ฒ• ์ œ8์กฐ 2ํ•ญ)
                </label>
              </div>
            </div>
          )}

          <div className="orderCheckButtonWrapper">
            {pageType === 'cart' ? (
              <Link to="/order/check" state={{ cartList }}>
                <Button>์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํ’ˆ ์ฃผ๋ฌธ</Button>
              </Link>
            ) : (
              <Button btnOnClick={onOrder}>๊ฒฐ์ œํ•˜๊ธฐ</Button>
            )}
          </div>
        </div>
      </div>
    </div>
  );
};
        
export default Order;

๋ฌผ๋ก  ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํ˜น์€ ๊ฒฐ์ œ์„œ์— ๋‹ด๊ฒจ์žˆ๋Š” ์ƒํ’ˆ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ปดํฌ๋„ŒํŠธ <Goods /> ๋˜ํ•œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ๊ฑธ์–ด์ฃผ์—ˆ๋‹ค.

Goods.js

import React from 'react';
import NumBtn from '../../../components/ProductInfoBox/NumBtn/NumBtn';
import { ReactComponent as Xbutton } from '../../../assets/Xbutton.svg';
import './Goods.scss';

const Goods = ({
  product: { cart_id, korean_name, thumbnail_image_url, price, quantity },
  pageType,
  deleteGoods,
  adjustTotalPrice,
  adjustCart,
}) => {
  const adjustQuantity = operator => {
    if (operator === 'minus') {
      if (quantity > 1) {
        adjustCart(cart_id, quantity - 1);
        adjustTotalPrice(operator, price);
      }
    } else if (operator === 'plus') {
      adjustCart(cart_id, quantity + 1);
      adjustTotalPrice(operator, price);
    }
  };

  return (
    <tbody className="goods">
      <tr className="tableRow">
        <td className="tableBody image">
          <div className="imageContainer">
            <img
              className="goodsImage"
              alt="example_goods"
              src={thumbnail_image_url}
            />
          </div>
        </td>
        <td className="tableBody goods">
          <p>{korean_name}</p>
        </td>
        <td className="tableBody quantity">
          {pageType === 'cart' ? (
            <NumBtn
              minusOne={() => adjustQuantity('minus')}
              plusOne={() => adjustQuantity('plus')}
              numValue={quantity}
            />
          ) : (
            quantity
          )}
        </td>
        <td className="tableBody price">
          <p>{price * quantity}์›</p>
        </td>
        <td className="tableBody goodsButton">
          {pageType === 'cart' && (
            <button
              className="deleteButton"
              onClick={() => deleteGoods(cart_id)}
            >
              <Xbutton />
            </button>
          )}
        </td>
      </tr>
    </tbody>
  );
};

export default Goods;

์žฅ๋ฐ”๊ตฌ๋‹ˆ ํŽ˜์ด์ง€์ผ ๊ฒฝ์šฐ ์‚ญ์ œ ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™” ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๊ณ ,

๊ฒฐ์ œ ์ง„ํ–‰๋ฒ„ํŠผ์ผ ๋•Œ๋Š” ๋‹จ์ˆœํ•œ ์ปดํฌ๋„ŒํŠธ๋กœ ์ž‘๋™ํ•˜๋„๋ก ํ•˜์˜€๋‹ค.

Query๋ฅผ ์ด์šฉํ•œ ๊ฒฐ์ œ์ •๋ณด id ๋„˜๊ฒจ์ฃผ๊ธฐ

ํ”„๋กœ์ ํŠธ ์ตœ์ข… Merge ํ•œ ์‹œ๊ฐ„ ์ „ ๋ฐฑ์—”๋“œ์˜ ์ •ํ˜„๋‹˜์ด ๋งˆ์ง€๋ง‰ ๊ฒฐ์ œ์ •๋ณด๋ฅผ ๋ฐ›๋Š” ๋กœ์ง์— ๋ณ€๊ฒฝ์ด ์ƒ๊ฒจ์„œ ์•ž๋‹จ์—์„œ๋„ ์ˆ˜์ •์„ ํ•ด์ฃผ์‹ค ์ˆ˜ ์žˆ๊ฒ ๋ƒ๋Š” ์งˆ๋ฌธ์„ ํ•˜์…จ๋‹ค.

์‹œ๊ฐ„์ด ์ด‰๋ฐ•ํ–ˆ์ง€๋งŒ, ์šฐ๋ฆฌํŒ€ ๋ฐฑ์—”๋“œ๋ฅผ ์œ„ํ•ด์„œ ์ข€๋งŒ ๋” ํž˜๋‚ด๊ธฐ๋กœ ํ–ˆ๋‹ค.

Order.js

const onOrder = async () => {
    if (isTermsChecked) {
      const orderTable = cartList.map(product => ({
        product_id: product.product_id,
        quantity: product.quantity,
      }));

      const data = await fetch(API_ADDRESS.order_checkout, {
        method: 'POST',
        headers: {
          Authorization: token,
        },
        body: JSON.stringify(orderTable),
      });

      const res = await data.json();

      navigate(`/order/confirm?order=${res.message}`);
    } else {
      window.alert('์•ฝ๊ด€์— ๋™์˜ํ•ด์ฃผ์…”์•ผ ๊ฒฐ์ œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.');
    }
  };

์›๋ž˜ ๊ฒฐ์ œ ์ดํ›„ ๊ฒฐ์ œ ์ •๋ณด๋ฅผ ๋ฐ›๋Š” ํŽ˜์ด์ง€์—์„œ ํ•ด๋‹น ์œ ์ €์˜ ๊ฐ€์žฅ ์ตœ๊ทผ ๊ฒฐ์ œ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๋ฐฉ์‹์ด์—ˆ์ง€๋งŒ,
์ •๋ณด๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ๋ณด๋‚ด์ค„ ์ˆ˜ ์žˆ๋„๋ก ๋ฐฑ์—”๋“œ์˜ ์ˆ˜์ •์ด ์žˆ์—ˆ๋‹ค.

๊ทธ๊ฒƒ์„ ์ •ํ™•ํ•˜๊ฒŒ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ์ฟผ๋ฆฌ์ŠคํŠธ๋ง์œผ๋กœ ๊ฒฐ์ œ์ •๋ณด ํ…Œ์ด๋ธ”์˜ ํ•ด๋‹น ๊ฒฐ์ œ ์ •๋ณด id๋ฅผ ๋ฐ›์•„ ๊ฒฐ์ œ ์™„๋ฃŒ ํŽ˜์ด์ง€๋กœ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •์„ ํ•˜์˜€๋‹ค.

์ด ํ›„ ๊ฒฐ์ œ ์™„๋ฃŒ ํŽ˜์ด์ง€์—์„œ๋Š” id๋ฅผ ์ด์šฉํ•ด ๊ฒฐ์ œ์ •๋ณด ํ…Œ์ด๋ธ”์—์„œ ํ•ด๋‹นํ•˜๋Š” ๊ฒฐ์ œ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค.

profile
Web Developer / Composer

1๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2021๋…„ 12์›” 19์ผ

๋„์—ฐ๋‹˜ ์งฑ

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ