Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- Java
- 백준
- 스택
- 리액트
- 오블완
- 알고리즘
- userprog
- pintos
- 모션비트
- 코드트리
- 소켓
- TiL
- 4기
- 시스템콜
- 티스토리챌린지
- CSS
- 사이드프로젝트
- 자바스크립트
- Vue.js
- corou
- HTML
- defee
- 크래프톤정글
- 크래프톤 정글
- JavaScript
- 자바
- Flutter
- 큐
- 나만무
- 핀토스
Archives
- Today
- Total
미새문지
24.10.01 day74 자투리 수정 본문
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
'개발 TIL' 카테고리의 다른 글
24.10.08 day76 Next.js (1) | 2024.10.08 |
---|---|
24.10.02 day75 브라우저의 데이터 저장방식 (1) | 2024.10.02 |
24.09.30 day73 작업 일지 (1) | 2024.09.30 |
24.09.26 day72 필터 구현, 무한스크롤, 폴링, 화면 처리 (0) | 2024.09.26 |
24.09.25 day71 작업 일지 (0) | 2024.09.25 |