React

React로 커머스 사이트 만들기 (5): 주문인증/주문조회 페이지

Jinmidnight 2023. 9. 24. 02:23
 

GitHub - jinmidnight01/powersell_frontend

Contribute to jinmidnight01/powersell_frontend development by creating an account on GitHub.

github.com

본 내용의 코드는 전부 위 링크에 있으니 참고바랍니다

 


주문인증 페이지 (AuthenticationPage.js)

 

useRef를 통해 Input focus

- 전화번호 중 지역번호는 2~3자리, 둘째 칸은 4자리, 마지막 칸은 4자리 형식으로 작성하면 다음 Input으로 focus

- 비밀번호는 4자리 형식으로 작성하면 제출버튼으로 focus

- 지역번호, 전화번호 둘째 칸, 전화번호 마지막 칸, 비밀번호, 제출버튼에 ref 속성 추가

...
  // 정규표현식
  const reg = useMemo(() => /^[0-9]{4}$/, []);

  // 지역번호에서 전화번호 둘째칸으로 이동
  useEffect(() => {
    if ((/^[0-9]{2,3}$/).test(number1)) {
      refNum2.current.focus();
    };
  }, [number1, reg]);

  // 전화번호 둘째칸에서 마지막 칸으로 이동
  useEffect(() => {
    if (reg.test(number2)) {
      refNum3.current.focus();
    };
  }, [number2, reg]);

  // 전화번호 마지막 칸에서 비밀번호 칸으로 이동
  useEffect(() => {
    if (reg.test(number3)) {
      refPw.current.focus();
    };
  }, [number3, reg]);

  // 비밀번호 칸에서 제출 버튼으로 이동
  useEffect(() => {
    if (reg.test(pw)) {
      submitFocus.current.focus();
    };
  }, [pw, reg]);
...

 

 

주문 인증 POST

1. 제어 컴포넌트로 인증 input 객체 생성

...
  // 전화번호(지역번호, 둘째칸, 마지막 칸), 비밀번호
  const [inputs, setInputs] = useState({
    number1: "010",
    number2: "",
    number3: "",
    pw: "",
  });

  const { number1, number2, number3, pw } = inputs;

  // input 객체 생성
  const onChange = (e) => {
    const { value, name } = e.target;
    setInputs({
      ...inputs,
      [name]: value,
    });
  };
...
return
...
  // 지역번호
  <select name="number1" onChange={onChange} value={number1} disabled={isPosting ? true : false}>
    <option value="010">010</option>
    <option value="070">070</option>
    <option value="011">011</option>
    <option value="02">02</option>
    <option value="031">031</option>
  </select>
...

2. input 객체 POST

- input 값 형식 확인 후 주문인증 POST 진행

- input 값 형식이 틀렸을 경우 style 변화로 맞는 형식 안내

- 주문인증 POST 시 loading 실행

- 인증 성공 시 pw값과 주문 정보인 response.data를 OrderConfirmPage로 넘겨줌과 동시에 이동

...
  // REST API 1-3: post authentication data
  const handleSubmit = (e) => {
    const flagNum2 = /^[0-9]{3,4}$/.test(number2);
    const flagNum3 = reg.test(number3);
    const flagPw = reg.test(pw);

    // prevent page reset
    e.preventDefault();

    // loading start
    setIsPosting(true);

    // input 형식 검사
    if (!flagNum2 || !flagNum3 || !flagPw) {
      setStyleInputs({
        ...styleInputs,
        numberNotiStyle: flagNum2 && flagNum3 ? {display: "none"} : {display: "block"},
        number2Style: flagNum2 ? {borderColor: "rgb(205, 205, 205)"} : {borderColor: "#fa7979", borderWidth: "2px"},
        number3Style: flagNum3 ? {borderColor: "rgb(205, 205, 205)"} : {borderColor: "#fa7979", borderWidth: "2px"},
        pwNotiStyle: flagPw ? {display: "none"} : {display: "block"},
        pwStyle: flagPw ? {borderColor: "rgb(205, 205, 205)"} : {borderColor: "#fa7979", borderWidth: "2px"}
      });
      setIsPosting(false);
      return;
    }

    // 주문 인증 POST
    const number = number1 + number2 + number3;
    const inputs = { number: number, pw: pw };

    axios
      .post(`${hostURL}/api/orders/detail`, inputs)
      .then((response) => {
        // 주문 내역이 없는 경우
        if (response.data.length === 0) {
          alert("해당 주문 내역이 없습니다");
          setIsPosting(false);
          return;
        }
        // 주문 내역이 있는 경우
        navigate("/orderconfirm", { state: response.data });
      })
      .catch((error) => {
        console.log(error);
      });
  };
...

 


주문조회 페이지 (OrderConfirmPage.js)

 

useLocation을 통해 response.data 받기

- useEffect를 통해 최초 렌더링 시에만 작동

- useState를 통해 output 상태를 전달받은 주문정보로 set

...
  const output = useLocation().state;
  const navigate = useNavigate();

  // response data
  useEffect(() => {
    // prevent direct URL access
    if (output === null) {
      navigate("/authentication");
    }
  });
...

 

Map 함수로 주문 나열

- sort 메소드를 통해 최신 순으로 나열

- key를 orderId로 설정

- 주문이 취소 됐을 경우 주문 일시와 함께 안내

- '입금 대기' 상태인 경우 추가 안내 첨부

return
...
  {/* item */}
  {[...output]
    .sort((a, b) => {
      if (a.orderDate > b.orderDate) return -1;
      if (a.orderDate < b.orderDate) return 1;
      return 0;
    })
    .map((order) => (
      <div key={order.orderId} className={styles.order_box}>
        <div className={styles.order_item}>
          {/* item title */}
          <div className={styles.order_itemTitle}>
            <div>
              <img src={itemImage(order)} alt={order.item.name} />
            </div>
            <div>
              <div>{order.item.name}</div>
              <div>
                {order.item.price}원 / {order.count}개
              </div>
            </div>
          </div>

          {order.orderStatus !== "CANCELED" ? ( ... ) :
          (
            <>
              {/* order cancel */}
              <div className={styles.order_cancel}>
                <div>
                  <span>주문 일시</span>: {order.orderDate.replace("T", " ").slice(0, 24)}
                </div>
                <div>※ 해당 주문은 취소되었습니다</div>
              </div>
            </>
          )}

          {/* payment notification */}
          {(order.orderStatus === "WAITING" ||
          order.orderStatus === null) && ( ... )}
      </div>
    ))}
...