미새문지

24.10.01 day74 자투리 수정 본문

개발 TIL

24.10.01 day74 자투리 수정

문미새 2024. 10. 1. 23:43
728x90

결제 페이지에서 배송지 변경을 위해 팝업창이 띄워져 있는 동안 기존 페이지의 기능을 막아달라는 요청을 받아 해당 기능을 구현했다.

import { useLocation, useNavigate } from "react-router-dom";
import AboutHeader from "../components/common/aboutHeader";
import MainFooter from "../components/common/mainFooter";
import BuyBtn from "../components/mart/buyBtn";
import styled from "styled-components";
import CertItem from "../components/mart/certItem";
import { useEffect, useState } from "react";
import axios from "axios";
import { useDispatch, useSelector } from "react-redux";
import { setSelectAddress } from "../redux/slice/addressSlice";

interface itemData {
  average_rating: number;
  brand_name: string;
  category: string;
  description: string;
  item_key: number;
  item_name: string;
  item_price: number;
  volume: number;
}

interface cartItem {
  cart_key: number;
  item: itemData;
  item_key: number;
  quantity: number;
  user_key: number;
}

interface totalPriceData {
  cartList: cartItem;
  totalPrice: number;
  totalQuantity: number;
}

interface addressData {
  address_key: number;
  address_name: string;
  name: string;
  addr: string;
  addr_detail: string;
  zip: string;
  tel: string;
  request: string;
  is_default: string;
}

const Cert: React.FC<totalPriceData> = () => {
  const navigate = useNavigate();
  const location = useLocation();
  const dispatch = useDispatch();
  const { cartList, totalPrice, totalQuantity } = location.state || {};
  const userKey = sessionStorage.getItem("userKey");
  const backPort = process.env.REACT_APP_BACKEND_PORT;
  const token = sessionStorage.getItem("authToken");
  const [addressList, setAddressList] = useState<addressData | null>(null);
  const selectAddress = useSelector(
    (state: any) => state.address.selectAddress
  );
  const [email, setEmail] = useState("");
  const [isModalOpen, setIsModalOpen] = useState(false);

  useEffect(() => {
    fetchSelfInfo();
    if (!selectAddress) {
      fetchDefaultAddress();
    }
  }, [selectAddress]);

  useEffect(() => {
    window.handleAddressChange = (newAddress) => {
      console.log("주소 업데이트 됨", newAddress);
      dispatch(setSelectAddress(newAddress));
    };
  }, [dispatch]);

  const fetchSelfInfo = async () => {
    try {
      const response = await axios.get(`${backPort}/api/user/${userKey}`, {
        headers: {
          Authorization: `Bearer ${token}`,
        },
      });
      setEmail(response.data.email);
      console.log(response.data);
    } catch (error) {
      console.error("주소지를 불러오는 중 오류 발생", error);
    }
  };

  const fetchDefaultAddress = async () => {
    try {
      const response = await axios.get(
        `${backPort}/api/user/${userKey}/address`,
        {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        }
      );
      setAddressList(response.data);
      const defaultAddr = response.data.find(
        (addr: addressData) => addr.is_default === "Y"
      );
      dispatch(setSelectAddress(defaultAddr || null));
    } catch (error) {
      console.error("주소지를 불러오는 중 오류 발생", error);
    }
  };

  const handleBack = () => {
    navigate(-1);
  };

  const handleAddressModalOpen = () => {
    setIsModalOpen(true);

    const popup = window.open(
      "/popup",
      "배송지 변경",
      "width=450,height=700,scrollbars=yes"
    );

    const handleFocus = () => {
      setIsModalOpen(false);
      window.removeEventListener("focus", handleFocus);
    };

    if (popup) {
      (popup as Window).handleAddressChange = (newAddress) => {
        console.log("주소 업데이트됨:", newAddress);
        dispatch(setSelectAddress(newAddress));
      };

      popup.onbeforeunload = () => {
        window.addEventListener("focus", handleFocus);
      };

      const handlePopupClose = setInterval(() => {
        if (popup.closed) {
          setIsModalOpen(false);
          clearInterval(handlePopupClose);
        }
      }, 500);
    }
  };

  const onOverlay = (event: React.MouseEvent<HTMLDivElement>) => {
    event.stopPropagation();
    console.log("Overlay clicked, but modal should not close.");
  };

  const handleAddressPage = () => {
    navigate("/mypage/setAddress");
  };

  return (
    <>
      {isModalOpen && <Overlay onClick={onOverlay} />}
      <AboutHeader Title="주문서" onBack={handleBack} />
      <CertWrapper>
        {!selectAddress ? (
          <NotAddress>
            <span>배송지가 설정되지 않았습니다.</span>
            <span>마이페이지로 이동하시겠습니까?</span>
            <button onClick={handleAddressPage}>이동</button>
          </NotAddress>
        ) : (
          <AddressBox>
            <AddressBoxTitle>
              <h3>{selectAddress?.address_name}</h3>
              <span onClick={handleAddressModalOpen}>배송지 변경</span>
            </AddressBoxTitle>
            <AddressBoxContent>
              <span>{selectAddress?.name}</span>
              <span>
                {selectAddress?.addr}({selectAddress?.zip})
              </span>
              <span>{selectAddress?.addr_detail}</span>
              <span>{selectAddress?.tel}</span>
              <span>{selectAddress?.request}</span>
              {selectAddress?.is_default === "Y" && (
                <DefaultAddr>기본 배송지</DefaultAddr>
              )}
            </AddressBoxContent>
          </AddressBox>
        )}
        <div>
          <h3>주문 상품 {totalQuantity}개</h3>
          {cartList.map((cartItem: cartItem) => (
            <CertItemBox key={cartItem.cart_key}>
              <span>제품 수량 : {cartItem.quantity}개</span>
              <CertItem item={cartItem.item} />
            </CertItemBox>
          ))}
        </div>
        <div className="priceListWrapper">
          <div className="priceListBox">
            <h3>결제 금액</h3>
            <div>
              <span>상품 금액</span>
              <span>{totalPrice.toLocaleString()}원</span>
            </div>
            <div>
              <span>할인 금액</span>
              <span>0원</span>
            </div>
            <div>
              <span>배송비</span>
              <span>0원</span>
            </div>
            <div>
              <span>총 결제 금액</span>
              <span>{totalPrice.toLocaleString()}원</span>
            </div>
          </div>
        </div>
        <BuyBtn
          cartList={cartList}
          totalPrice={totalPrice}
          selectAddress={selectAddress}
          email={email}
        />
      </CertWrapper>
      <MainFooter />
    </>
  );
};
export default Cert;

useState를 이용해 boolean 타입의 상태관리 변수를 만들고 팝업창이 열리면 해당 변수가 true가 되면서 기존 페이지 위에 오버레이 div가 덮이게 된다. 해당 오버레이로 버튼이나 다른 기능을 못누르게 막고 팝업창을 끄거나 배송지 선택을 했을 때 팝업 창이 꺼지며 꺼진 걸 감지했을 때 다시 변수가 false가 되면서 오버레이가 꺼지게 된다.


그리고 결제 페이지에서 배송지가 없을 경우 그냥 빈 박스만 표시되게 되어 이 부분을 다른 컴포넌트로 처리하고 버튼 클릭 시 마이페이지의 배송지 관리 페이지로 넘어가게 했다.


그리고 포트폴리오를 위해 모든 페이지와 기능 구현이 시각적으로 보여지는 페이지들을 전부 캡처해놨다.

이거가지고 야무지게 포트폴리오 만들어서 얼른 취업해야지 후..

728x90