From 5696b53acecaf119f4f391b3f105d81fdd03c9e6 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Wed, 10 Jan 2024 11:43:29 +0900 Subject: [PATCH 01/26] =?UTF-8?q?refactor:=20rel=3D"noopener"=20=EC=86=8D?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx b/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx index 6d8d2763..03cb040f 100644 --- a/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx +++ b/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx @@ -88,6 +88,7 @@ const RoomInfo = ({ room }: RoomInfoProps) => { From 165238631ade3d2b164311bcc47ded5c150462c2 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Fri, 12 Jan 2024 15:33:08 +0900 Subject: [PATCH 02/26] =?UTF-8?q?design:=20=EC=83=81=ED=92=88=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=ED=83=80=EC=9D=B4?= =?UTF-8?q?=ED=8B=80=20=EB=A7=90=EC=A4=84=EC=9E=84=ED=91=9C=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomDetailPage/components/roomHeader/RoomHeader.style.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts index e850c2bb..a86be054 100644 --- a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts +++ b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts @@ -61,6 +61,7 @@ export const TitleWrapper = styled.div` overflow: hidden; text-overflow: ellipsis; text-align: center; + width: 100%; `; export const Title = styled.p<{ $visible: boolean }>` From 2b0d173f12fc8c62992f0d959f7a4cca8fc626d6 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:04:34 +0900 Subject: [PATCH 03/26] =?UTF-8?q?fix:=20Gobal=20Suspense=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.tsx | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/main.tsx b/src/main.tsx index 857ae0d2..b2fe260a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,10 +1,9 @@ -import React, { Suspense } from "react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import ReactDOM from "react-dom/client"; import { RouterProvider } from "react-router-dom"; import { ThemeProvider } from "styled-components"; -import { worker } from "./mocks/broswer.ts"; +import { worker } from "./mocks/broswer"; import { router } from "./routes/router"; import { GlobalStyle } from "./styles/globalStyle"; import { theme } from "./styles/theme"; @@ -15,15 +14,11 @@ if (process.env.NODE_ENV === "development") { } ReactDOM.createRoot(document.getElementById("root")!).render( - - - - - {/* Global Loading... */}}> - - - - - - , + + + + + + + , ); From 38633316d931a53be306809a17db4dc9c4b4491c Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:04:58 +0900 Subject: [PATCH 04/26] =?UTF-8?q?refactor:=20=EB=9D=BC=EC=9A=B0=ED=84=B0?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/router.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/router.tsx b/src/routes/router.tsx index da781463..b3f6fb02 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -162,11 +162,11 @@ export const router = createBrowserRouter([ element: , children: [ { - index: true, + path: ":productId", element: , }, { - path: "success", + path: "success/:productId", element: , }, ], From 7a0f28988fb849c342e87952d638fedc35e02e7b Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:05:29 +0900 Subject: [PATCH 05/26] =?UTF-8?q?fix:=20room=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/fetchRoom.ts | 8 ++++++-- src/mocks/data/dummyRoomDetail.json | 3 ++- src/types/room.ts | 5 +++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/apis/fetchRoom.ts b/src/apis/fetchRoom.ts index 5afe5a57..c4ee6b71 100644 --- a/src/apis/fetchRoom.ts +++ b/src/apis/fetchRoom.ts @@ -1,7 +1,11 @@ import { axiosInstance } from "@apis/axiosInstance"; import { END_POINTS } from "@constants/api"; +import type { ResponseData } from "@type/responseType"; +import type { RoomData } from "@type/room"; -export const getRoom = async (roomId: string) => { - const { data } = await axiosInstance.get(END_POINTS.ROOM(roomId)); +export const getRoom = async (roomId: string): Promise => { + const { data } = await axiosInstance.get>( + END_POINTS.ROOM(roomId), + ); return data.data; }; diff --git a/src/mocks/data/dummyRoomDetail.json b/src/mocks/data/dummyRoomDetail.json index 23e03027..263b10e7 100644 --- a/src/mocks/data/dummyRoomDetail.json +++ b/src/mocks/data/dummyRoomDetail.json @@ -21,7 +21,8 @@ }, "hotelAddress": "서울특별시 강남구 테헤란로 99길 9", "hotelInfoUrl": "https://place-site.yanolja.com/places/3001615", - "saleStatus": false + "saleStatus": false, + "isSeller": true }, "message": "상품 조회에 성공했습니다." } diff --git a/src/types/room.ts b/src/types/room.ts index 5616a5bb..947a7722 100644 --- a/src/types/room.ts +++ b/src/types/room.ts @@ -1,7 +1,7 @@ export type RoomData = { hotelName: string; roomName: string; - hotelImageUrl: string[]; + hotelImageUrlList: string[]; checkIn: string; checkOut: string; originalPrice: number; @@ -13,6 +13,7 @@ export type RoomData = { hotelAddress: string; hotelInfoUrl: string; saleStatus: boolean; + isSeller: boolean; }; type RoomTheme = { parkingZone: boolean; @@ -23,5 +24,5 @@ type RoomTheme = { export type RoomNavBarData = Pick< RoomData, - "originalPrice" | "sellingPrice" | "saleStatus" + "originalPrice" | "sellingPrice" | "saleStatus" | "isSeller" >; From 4671ad4f76c6a3e5b8cdba43bc5a32cffd999c8d Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:05:44 +0900 Subject: [PATCH 06/26] =?UTF-8?q?fix:=20=EC=BA=90=EB=A1=9C=EC=85=80=20widt?= =?UTF-8?q?h=20=EA=B0=92=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/carousel/Carousel.style.ts | 2 -- src/components/carousel/Carousel.tsx | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/carousel/Carousel.style.ts b/src/components/carousel/Carousel.style.ts index 0820b746..3595b001 100644 --- a/src/components/carousel/Carousel.style.ts +++ b/src/components/carousel/Carousel.style.ts @@ -3,11 +3,9 @@ import styled, { css } from "styled-components"; export const CarouselContainer = styled.div<{ $height: number; - $width: number; }>` position: relative; - width: ${(props) => `${props.$width}px`}; min-height: ${(props) => `${props.$height}px`}; height: ${(props) => `${props.$height}px`}; diff --git a/src/components/carousel/Carousel.tsx b/src/components/carousel/Carousel.tsx index 61ea6f3c..f7d102e5 100644 --- a/src/components/carousel/Carousel.tsx +++ b/src/components/carousel/Carousel.tsx @@ -4,7 +4,6 @@ import * as S from "./Carousel.style.ts"; interface CarouselProps { images: string[]; - width?: number; height?: number; arrows?: boolean; infinite?: boolean; @@ -14,7 +13,6 @@ interface CarouselProps { const Carousel = ({ height = 300, - width = 300, images, arrows = true, infinite = false, @@ -41,7 +39,7 @@ const Carousel = ({ }); return ( - + Date: Tue, 23 Jan 2024 17:06:34 +0900 Subject: [PATCH 07/26] =?UTF-8?q?refactor:=20=EC=83=81=EC=84=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A1=B0=ED=9A=8C=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/api/useRoomQuery.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/hooks/api/useRoomQuery.ts diff --git a/src/hooks/api/useRoomQuery.ts b/src/hooks/api/useRoomQuery.ts new file mode 100644 index 00000000..a846728c --- /dev/null +++ b/src/hooks/api/useRoomQuery.ts @@ -0,0 +1,28 @@ +import { useSuspenseQuery } from "@tanstack/react-query"; +import { getRoom } from "@apis/fetchRoom"; +import { calculateDiscount } from "@utils/calculator"; + +import type { RoomData } from "@type/room"; +import type { AxiosError } from "axios"; + +interface RoomQueryData { + rawData: RoomData; + discountRate: string; +} + +export const useRoomQuery = (roomId: string) => { + return useSuspenseQuery({ + queryKey: ["room", roomId], + queryFn: () => getRoom(roomId), + select: (data) => { + const discountRate = calculateDiscount( + data.originalPrice, + data.sellingPrice, + ); + return { + rawData: data, + discountRate, + }; + }, + }); +}; From 882ae3d9473d688269e38b316702eb383eb7ab3c Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:07:53 +0900 Subject: [PATCH 08/26] =?UTF-8?q?refactor:=20=EA=B2=B0=EC=A0=9C=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20Params=EB=A1=9C=20product=20id=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/paymentPage/Payment.tsx | 10 +++++----- .../components/paymentButton/PaymentButton.tsx | 7 +++---- src/pages/paymentSuccessPage/PaymentSuccess.tsx | 10 +++++----- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/pages/paymentPage/Payment.tsx b/src/pages/paymentPage/Payment.tsx index 26d81629..1d762265 100644 --- a/src/pages/paymentPage/Payment.tsx +++ b/src/pages/paymentPage/Payment.tsx @@ -4,17 +4,17 @@ import PaymentMethodSection from "@/pages/paymentPage/components/paymentMethodSe import TermsAgreementSection from "@/pages/paymentPage/components/termsAgreementSection/TermsAgreementSection"; import UserInfoSection from "@/pages/paymentPage/components/userInfoSection/UserInfoSection"; import { usePaymentQuery } from "@hooks/api/query/usePaymentQuery"; -import { useSearchParams } from "react-router-dom"; +import { useParams } from "react-router-dom"; import PaymentButton from "./components/paymentButton/PaymentButton"; import { FormProvider, useForm } from "react-hook-form"; import Caption from "@components/caption/Caption"; const Payment = () => { - const [searchParams] = useSearchParams(); - const product = searchParams.get("product") ?? ""; + const { productId } = useParams(); + if (!productId) throw Error("존재하지 않는 productId 입니다."); - const { data } = usePaymentQuery(product); + const { data } = usePaymentQuery(productId); const methods = useForm({ mode: "onChange", @@ -47,7 +47,7 @@ const Payment = () => { - + diff --git a/src/pages/paymentPage/components/paymentButton/PaymentButton.tsx b/src/pages/paymentPage/components/paymentButton/PaymentButton.tsx index 6f968af7..b90473d5 100644 --- a/src/pages/paymentPage/components/paymentButton/PaymentButton.tsx +++ b/src/pages/paymentPage/components/paymentButton/PaymentButton.tsx @@ -2,14 +2,13 @@ import { useFormContext } from "react-hook-form"; import { usePaymentMutation } from "@hooks/api/mutation/usePaymentMutation"; import * as S from "./PaymentButton.style"; -import type { PaymentData } from "@type/payment"; interface PaymentButtonProps { productId: string; - payment: Pick; + price: number; } -const PaymentButton = ({ productId, payment }: PaymentButtonProps) => { +const PaymentButton = ({ productId, price }: PaymentButtonProps) => { const { handleSubmit, getValues, @@ -55,7 +54,7 @@ const PaymentButton = ({ productId, payment }: PaymentButtonProps) => { data-disabled={isValid ? null : ""} aria-label="결제하기" > - {payment.salePrice.toLocaleString("ko-KR")}원 결제하기 + {price.toLocaleString("ko-KR")}원 결제하기 ); }; diff --git a/src/pages/paymentSuccessPage/PaymentSuccess.tsx b/src/pages/paymentSuccessPage/PaymentSuccess.tsx index 93a52337..9f0667a0 100644 --- a/src/pages/paymentSuccessPage/PaymentSuccess.tsx +++ b/src/pages/paymentSuccessPage/PaymentSuccess.tsx @@ -1,4 +1,4 @@ -import { useSearchParams } from "react-router-dom"; +import { useParams } from "react-router-dom"; import { usePurchaseDetailQuery } from "@hooks/api/query/usePurchaseQuery"; import PaymentSuccessInfo from "@pages/paymentSuccessPage/components/PaymentSuccessInfo/PaymentSuccessInfo"; @@ -9,10 +9,10 @@ import CardItem from "@components/cardItem/CardItem"; import * as S from "./PaymentSuccess.style"; const PaymentSuccess = () => { - const [searchParams] = useSearchParams(); - const product = searchParams.get("product") ?? ""; + const { productId } = useParams(); + if (!productId) throw Error("존재하지 않는 productId 입니다."); - const { data } = usePurchaseDetailQuery(product); + const { data } = usePurchaseDetailQuery(productId); return ( @@ -63,7 +63,7 @@ const PaymentSuccess = () => { - + ); From 10ac7a9cd44774bc28aade50939e84e1bda602c9 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:08:18 +0900 Subject: [PATCH 09/26] =?UTF-8?q?design:=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20fixed=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/toast/Toast.style.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/toast/Toast.style.ts b/src/components/toast/Toast.style.ts index da782af1..74c1b9a4 100644 --- a/src/components/toast/Toast.style.ts +++ b/src/components/toast/Toast.style.ts @@ -16,7 +16,7 @@ export const ToastContainer = styled(motion.div)<{ $isError: boolean }>` justify-content: center; align-items: center; - position: absolute; + position: fixed; left: 0; right: 0; top: 80px; From edaae88b3d9c413d61cc809a2021a3387c5aa845 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:09:00 +0900 Subject: [PATCH 10/26] =?UTF-8?q?fix:=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=EC=9A=94=EC=B2=AD=20=ED=9B=85=20throwOnError?= =?UTF-8?q?=EC=97=90=20=EC=A1=B0=EA=B1=B4=20=EA=B1=B8=EC=96=B4=EC=84=9C=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EB=8D=98=EC=A7=80=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/api/mutation/useValidateEmailMutation.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hooks/api/mutation/useValidateEmailMutation.ts b/src/hooks/api/mutation/useValidateEmailMutation.ts index 8bebda67..5d11f5db 100644 --- a/src/hooks/api/mutation/useValidateEmailMutation.ts +++ b/src/hooks/api/mutation/useValidateEmailMutation.ts @@ -1,10 +1,13 @@ import { postValidateEmail } from "@apis/fetchLogin"; import { useMutation } from "@tanstack/react-query"; +import { isAxiosError } from "axios"; export const useValidateEmailMutation = () => { const validateEmailMutation = useMutation({ mutationFn: ({ email }: { email: string }) => postValidateEmail(email), - throwOnError: true, + throwOnError: (error) => { + return !(isAxiosError(error) && error.response); + }, }); return validateEmailMutation; From c4923e9445f8f89c0116a62f59a99724cef9aaa4 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:09:20 +0900 Subject: [PATCH 11/26] =?UTF-8?q?design:=20=EC=B2=B4=ED=81=AC=EB=B0=95?= =?UTF-8?q?=EC=8A=A4=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/checkbox/Checkbox.style.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/checkbox/Checkbox.style.ts b/src/components/checkbox/Checkbox.style.ts index 81958ef4..b7b1d892 100644 --- a/src/components/checkbox/Checkbox.style.ts +++ b/src/components/checkbox/Checkbox.style.ts @@ -1,4 +1,4 @@ -import styled, { DefaultTheme } from "styled-components"; +import styled, { DefaultTheme, css } from "styled-components"; export interface CheckboxStyleProps { size?: "sm" | "md" | "lg"; @@ -117,11 +117,11 @@ export const StyledCheckbox = styled.span` `; const labelStyles = { - title: (theme: DefaultTheme) => ` + title: (theme: DefaultTheme) => css` color: ${theme.color.greyScale1}; } `, - caption: (theme: DefaultTheme) => ` + caption: (theme: DefaultTheme) => css` color: ${theme.color.greyScale3}; } `, @@ -140,8 +140,6 @@ export const LabelText = styled.span.withConfig({ ${({ theme }) => theme.typo.caption1} - ${({ variant, theme }) => variant && labelStyles[variant](theme)}; - margin-inline-start: 0.5rem; user-select: none; @@ -150,4 +148,6 @@ export const LabelText = styled.span.withConfig({ text-underline-offset: 2px; color: inherit; } + + ${({ variant, theme }) => variant && labelStyles[variant](theme)}; `; From 251e62861e227085a3ff27f8d616a827d8e49384 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:09:44 +0900 Subject: [PATCH 12/26] =?UTF-8?q?feat:=20=EC=83=81=EC=84=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EA=B5=AC=EB=A7=A4=EC=97=B0=EA=B2=B0,=20?= =?UTF-8?q?=ED=97=A4=EB=8D=94=20=EB=92=A4=EB=A1=9C=EA=B0=80=EA=B8=B0=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/roomDetailPage/RoomDetail.tsx | 32 ++++++++++------- .../components/roomHeader/RoomHeader.style.ts | 13 ++++--- .../components/roomHeader/RoomHeader.tsx | 13 +++++-- .../components/roomInfo/RoomInfo.tsx | 11 +++--- .../components/roomNavBar/RoomNavBar.style.ts | 3 +- .../components/roomNavBar/RoomNavBar.tsx | 35 +++++++++++++++---- 6 files changed, 72 insertions(+), 35 deletions(-) diff --git a/src/pages/roomDetailPage/RoomDetail.tsx b/src/pages/roomDetailPage/RoomDetail.tsx index ffdc7931..de7b00f0 100644 --- a/src/pages/roomDetailPage/RoomDetail.tsx +++ b/src/pages/roomDetailPage/RoomDetail.tsx @@ -1,38 +1,44 @@ -import { getRoom } from "@apis/fetchRoom"; - import Carousel from "@components/carousel/Carousel"; import RoomHeader from "@pages/roomDetailPage/components/roomHeader/RoomHeader"; import RoomInfo from "@pages/roomDetailPage/components/roomInfo/RoomInfo"; import RoomNavBar from "@pages/roomDetailPage/components/roomNavBar/RoomNavBar"; -import { useSuspenseQuery } from "@tanstack/react-query"; -import type { RoomData } from "@type/room"; -import type { AxiosError } from "axios"; + +import useToastConfig from "@hooks/common/useToastConfig"; +import { useRoomQuery } from "@hooks/api/useRoomQuery"; import { useParams } from "react-router-dom"; import * as S from "./RoomDetail.style"; +import { useEffect } from "react"; const RoomDetail = () => { const { roomId } = useParams(); if (!roomId) throw new Error("존재하지 않는 roomId 입니다."); - const { data } = useSuspenseQuery({ - queryKey: ["room"], - queryFn: () => getRoom(roomId), - }); + const { data } = useRoomQuery(roomId); + const { rawData, discountRate } = data; + + const { handleToast } = useToastConfig(); + + useEffect(() => { + if (rawData.isSeller) { + handleToast(false, ["내가 판매 중인 상품입니다"]); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [rawData.isSeller]); return ( - + - - + + ); }; diff --git a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts index a86be054..5471ab90 100644 --- a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts +++ b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts @@ -8,22 +8,25 @@ export const ScrollObserver = styled.div` `; export const HeaderContainer = styled.header<{ $visible: boolean }>` - display: flex; - align-items: center; position: fixed; top: 0; + + display: flex; + align-items: center; width: 100%; max-width: 768px; height: 56px; - z-index: 2; + background-color: ${({ $visible, theme }) => - $visible ? "unset" : theme.color.white}; + $visible ? "transparent" : theme.color.white}; border-bottom: ${({ $visible, theme }) => - $visible ? "none" : `1px solid ${theme.color.greyScale7}`}; + $visible ? "0" : `1px solid ${theme.color.greyScale7}`}; transition: border-bottom, background-color 0.5s ease-in; + + z-index: 2; `; export const Wrapper = styled.div` diff --git a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.tsx b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.tsx index 02413f20..7bea78ee 100644 --- a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.tsx +++ b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.tsx @@ -1,5 +1,7 @@ import useIsVisible from "@hooks/common/useIsVisible"; + import * as S from "./RoomHeader.style"; +import { useNavigate } from "react-router-dom"; interface RoomHeaderProps { title: string; @@ -11,15 +13,22 @@ const RoomHeader = ({ title }: RoomHeaderProps) => { rootMargin: "0px", threshold: 1.0, }, - initialVisible: false, + initialVisible: true, }); + const navigate = useNavigate(); + return ( <>
-
diff --git a/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx b/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx index 03cb040f..199e38e5 100644 --- a/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx +++ b/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx @@ -1,19 +1,18 @@ import RoomThemeOption from "@pages/roomDetailPage/components/roomThemeOption/RoomThemeOption"; -import * as S from "@pages/roomDetailPage/RoomDetail.style"; import type { RoomData } from "@type/room"; -import { calculateDiscount } from "@utils/calculator"; import { formatDate } from "@utils/dateFormatter"; import IconBed from "@assets/icons/ic_bed.svg?react"; import IconCaretRight from "@assets/icons/ic_caret_right.svg?react"; import IconUser from "@assets/icons/ic_users.svg?react"; +import * as S from "@pages/roomDetailPage/RoomDetail.style"; + interface RoomInfoProps { room: RoomData; + discount: string; } -const RoomInfo = ({ room }: RoomInfoProps) => { - const discountRate = calculateDiscount(room.originalPrice, room.sellingPrice); - +const RoomInfo = ({ room, discount }: RoomInfoProps) => { const checkInDate = formatDate(room.checkIn); const checkOutDate = formatDate(room.checkOut); return ( @@ -35,7 +34,7 @@ const RoomInfo = ({ room }: RoomInfoProps) => { 판매가 - {discountRate}% + {discount}% {room.sellingPrice.toLocaleString()}원 diff --git a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts index 6d56ed74..b895cc6b 100644 --- a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts +++ b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts @@ -33,7 +33,6 @@ export const Row2 = styled(Flex)` gap: 0.5rem; `; -// FIXME: Button 컴포넌트 만들기 export const Button = styled.button<{ $status: boolean }>` ${({ theme }) => theme.typo.button2} padding: 0.7rem 3rem; @@ -41,7 +40,7 @@ export const Button = styled.button<{ $status: boolean }>` border-radius: 8px; background-color: ${({ $status, theme }) => $status ? theme.color.percentOrange : theme.color.greyScale5}; - transition: background-color 0.5s ease-in; + transition: background-color 0.2s ease-in; &:hover { background-color: ${({ $status, theme }) => diff --git a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx index 831d2dc5..59ddd833 100644 --- a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx +++ b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx @@ -1,14 +1,30 @@ -import { RoomNavBarData } from "@type/room"; -import { calculateDiscount } from "@utils/calculator"; +import { useNavigate } from "react-router-dom"; +import type { RoomNavBarData } from "@type/room"; +import { PATH } from "@constants/path"; +import useToastConfig from "@hooks/common/useToastConfig"; + import * as S from "./RoomNavBar.style"; interface RoomNavBarProps { room: RoomNavBarData; + roomId: string; + discount: string; } -const RoomNavBar = ({ room }: RoomNavBarProps) => { - // FIXME: 패칭 후 가공단계에서 할인율 계산 - const discountRate = calculateDiscount(room.originalPrice, room.sellingPrice); +const RoomNavBar = ({ room, roomId, discount }: RoomNavBarProps) => { + const navigate = useNavigate(); + const { handleToast } = useToastConfig(); + + const handlePurchaseClick = () => { + if (room.isSeller) { + handleToast(true, [<>내가 판매하는 상품은 구매가 불가합니다]); + return; + } else if (!room.saleStatus) { + return; + } + + navigate(`${PATH.PAYMENT}/${roomId}`); + }; return ( @@ -18,14 +34,19 @@ const RoomNavBar = ({ room }: RoomNavBarProps) => { - {discountRate}% + {discount}% {room.sellingPrice.toLocaleString()}원 - + 구매하기
From a51184aa3b888d79275032781dab49676c6ac115 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:10:32 +0900 Subject: [PATCH 13/26] =?UTF-8?q?fix:=20useIsVisible=20=ED=9B=85=EC=97=90?= =?UTF-8?q?=EC=84=9C=20isVisible=EC=83=81=ED=83=9C=EA=B0=80=20=EB=B0=94?= =?UTF-8?q?=EB=80=94=20=EB=95=8C=EB=A7=8C=20observer=EA=B0=80=20=ED=99=9C?= =?UTF-8?q?=EC=84=B1=ED=99=94=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/common/useIsVisible.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hooks/common/useIsVisible.ts b/src/hooks/common/useIsVisible.ts index f0d6a7a5..582ebfb9 100644 --- a/src/hooks/common/useIsVisible.ts +++ b/src/hooks/common/useIsVisible.ts @@ -17,12 +17,13 @@ const useIsVisible = (props: UseIsVisibleProps): UseIsVisibleReturnType => { useEffect(() => { const observer = new IntersectionObserver(([entry]) => { - setIsVisible(entry.isIntersecting); + if (entry.isIntersecting !== isVisible) { + setIsVisible(entry.isIntersecting); + } }, options); if (visibleRef) { observer.observe(visibleRef); - return; } return () => { @@ -30,7 +31,7 @@ const useIsVisible = (props: UseIsVisibleProps): UseIsVisibleReturnType => { observer.unobserve(visibleRef); } }; - }, [options, visibleRef]); + }, [options, visibleRef, isVisible]); const setRefCallback: RefCallback = (node) => { setVisibleRef(node); From 2e3299bd7af864982646d44139c3febfc3244663 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Wed, 10 Jan 2024 11:43:29 +0900 Subject: [PATCH 14/26] =?UTF-8?q?refactor:=20rel=3D"noopener"=20=EC=86=8D?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx b/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx index 6d8d2763..03cb040f 100644 --- a/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx +++ b/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx @@ -88,6 +88,7 @@ const RoomInfo = ({ room }: RoomInfoProps) => {
From 3c699267c684b5dfa5e70dceb9ddb77ea1d6479b Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Fri, 12 Jan 2024 15:33:08 +0900 Subject: [PATCH 15/26] =?UTF-8?q?design:=20=EC=83=81=ED=92=88=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=ED=83=80=EC=9D=B4?= =?UTF-8?q?=ED=8B=80=20=EB=A7=90=EC=A4=84=EC=9E=84=ED=91=9C=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomDetailPage/components/roomHeader/RoomHeader.style.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts index e850c2bb..a86be054 100644 --- a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts +++ b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts @@ -61,6 +61,7 @@ export const TitleWrapper = styled.div` overflow: hidden; text-overflow: ellipsis; text-align: center; + width: 100%; `; export const Title = styled.p<{ $visible: boolean }>` From 7d56f64e82591e3575f2c40b83d8bacb0fc30524 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:04:34 +0900 Subject: [PATCH 16/26] =?UTF-8?q?fix:=20Gobal=20Suspense=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.tsx | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/main.tsx b/src/main.tsx index 857ae0d2..b2fe260a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,10 +1,9 @@ -import React, { Suspense } from "react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import ReactDOM from "react-dom/client"; import { RouterProvider } from "react-router-dom"; import { ThemeProvider } from "styled-components"; -import { worker } from "./mocks/broswer.ts"; +import { worker } from "./mocks/broswer"; import { router } from "./routes/router"; import { GlobalStyle } from "./styles/globalStyle"; import { theme } from "./styles/theme"; @@ -15,15 +14,11 @@ if (process.env.NODE_ENV === "development") { } ReactDOM.createRoot(document.getElementById("root")!).render( - - - - - {/* Global Loading... */}}> - - - - - - , + + + + + + + , ); From ddf17344bd56915589a649408d9bface477c672f Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:04:58 +0900 Subject: [PATCH 17/26] =?UTF-8?q?refactor:=20=EB=9D=BC=EC=9A=B0=ED=84=B0?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/router.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/router.tsx b/src/routes/router.tsx index f49438f3..bc06de3d 100644 --- a/src/routes/router.tsx +++ b/src/routes/router.tsx @@ -180,11 +180,11 @@ export const router = createBrowserRouter([ ), children: [ { - index: true, + path: ":productId", element: , }, { - path: "success", + path: "success/:productId", element: , }, ], From 71b182777bb09b66d142eb225a4f508b204725d8 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:05:29 +0900 Subject: [PATCH 18/26] =?UTF-8?q?fix:=20room=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/fetchRoom.ts | 8 ++++++-- src/mocks/data/dummyRoomDetail.json | 3 ++- src/types/room.ts | 5 +++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/apis/fetchRoom.ts b/src/apis/fetchRoom.ts index 5afe5a57..c4ee6b71 100644 --- a/src/apis/fetchRoom.ts +++ b/src/apis/fetchRoom.ts @@ -1,7 +1,11 @@ import { axiosInstance } from "@apis/axiosInstance"; import { END_POINTS } from "@constants/api"; +import type { ResponseData } from "@type/responseType"; +import type { RoomData } from "@type/room"; -export const getRoom = async (roomId: string) => { - const { data } = await axiosInstance.get(END_POINTS.ROOM(roomId)); +export const getRoom = async (roomId: string): Promise => { + const { data } = await axiosInstance.get>( + END_POINTS.ROOM(roomId), + ); return data.data; }; diff --git a/src/mocks/data/dummyRoomDetail.json b/src/mocks/data/dummyRoomDetail.json index 23e03027..263b10e7 100644 --- a/src/mocks/data/dummyRoomDetail.json +++ b/src/mocks/data/dummyRoomDetail.json @@ -21,7 +21,8 @@ }, "hotelAddress": "서울특별시 강남구 테헤란로 99길 9", "hotelInfoUrl": "https://place-site.yanolja.com/places/3001615", - "saleStatus": false + "saleStatus": false, + "isSeller": true }, "message": "상품 조회에 성공했습니다." } diff --git a/src/types/room.ts b/src/types/room.ts index 5616a5bb..947a7722 100644 --- a/src/types/room.ts +++ b/src/types/room.ts @@ -1,7 +1,7 @@ export type RoomData = { hotelName: string; roomName: string; - hotelImageUrl: string[]; + hotelImageUrlList: string[]; checkIn: string; checkOut: string; originalPrice: number; @@ -13,6 +13,7 @@ export type RoomData = { hotelAddress: string; hotelInfoUrl: string; saleStatus: boolean; + isSeller: boolean; }; type RoomTheme = { parkingZone: boolean; @@ -23,5 +24,5 @@ type RoomTheme = { export type RoomNavBarData = Pick< RoomData, - "originalPrice" | "sellingPrice" | "saleStatus" + "originalPrice" | "sellingPrice" | "saleStatus" | "isSeller" >; From 98d661c6b7565534346479383d25a9c639ae6201 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:05:44 +0900 Subject: [PATCH 19/26] =?UTF-8?q?fix:=20=EC=BA=90=EB=A1=9C=EC=85=80=20widt?= =?UTF-8?q?h=20=EA=B0=92=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/carousel/Carousel.style.ts | 2 -- src/components/carousel/Carousel.tsx | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/carousel/Carousel.style.ts b/src/components/carousel/Carousel.style.ts index 0820b746..3595b001 100644 --- a/src/components/carousel/Carousel.style.ts +++ b/src/components/carousel/Carousel.style.ts @@ -3,11 +3,9 @@ import styled, { css } from "styled-components"; export const CarouselContainer = styled.div<{ $height: number; - $width: number; }>` position: relative; - width: ${(props) => `${props.$width}px`}; min-height: ${(props) => `${props.$height}px`}; height: ${(props) => `${props.$height}px`}; diff --git a/src/components/carousel/Carousel.tsx b/src/components/carousel/Carousel.tsx index 61ea6f3c..f7d102e5 100644 --- a/src/components/carousel/Carousel.tsx +++ b/src/components/carousel/Carousel.tsx @@ -4,7 +4,6 @@ import * as S from "./Carousel.style.ts"; interface CarouselProps { images: string[]; - width?: number; height?: number; arrows?: boolean; infinite?: boolean; @@ -14,7 +13,6 @@ interface CarouselProps { const Carousel = ({ height = 300, - width = 300, images, arrows = true, infinite = false, @@ -41,7 +39,7 @@ const Carousel = ({ }); return ( - + Date: Tue, 23 Jan 2024 17:06:34 +0900 Subject: [PATCH 20/26] =?UTF-8?q?refactor:=20=EC=83=81=EC=84=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A1=B0=ED=9A=8C=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/api/useRoomQuery.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/hooks/api/useRoomQuery.ts diff --git a/src/hooks/api/useRoomQuery.ts b/src/hooks/api/useRoomQuery.ts new file mode 100644 index 00000000..a846728c --- /dev/null +++ b/src/hooks/api/useRoomQuery.ts @@ -0,0 +1,28 @@ +import { useSuspenseQuery } from "@tanstack/react-query"; +import { getRoom } from "@apis/fetchRoom"; +import { calculateDiscount } from "@utils/calculator"; + +import type { RoomData } from "@type/room"; +import type { AxiosError } from "axios"; + +interface RoomQueryData { + rawData: RoomData; + discountRate: string; +} + +export const useRoomQuery = (roomId: string) => { + return useSuspenseQuery({ + queryKey: ["room", roomId], + queryFn: () => getRoom(roomId), + select: (data) => { + const discountRate = calculateDiscount( + data.originalPrice, + data.sellingPrice, + ); + return { + rawData: data, + discountRate, + }; + }, + }); +}; From 7a53c802e55c1ecb2172c2db59fada7e5f9cbaea Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:07:53 +0900 Subject: [PATCH 21/26] =?UTF-8?q?refactor:=20=EA=B2=B0=EC=A0=9C=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20Params=EB=A1=9C=20product=20id=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/paymentPage/Payment.tsx | 10 +++++----- .../components/paymentButton/PaymentButton.tsx | 7 +++---- src/pages/paymentSuccessPage/PaymentSuccess.tsx | 10 +++++----- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/pages/paymentPage/Payment.tsx b/src/pages/paymentPage/Payment.tsx index 26d81629..1d762265 100644 --- a/src/pages/paymentPage/Payment.tsx +++ b/src/pages/paymentPage/Payment.tsx @@ -4,17 +4,17 @@ import PaymentMethodSection from "@/pages/paymentPage/components/paymentMethodSe import TermsAgreementSection from "@/pages/paymentPage/components/termsAgreementSection/TermsAgreementSection"; import UserInfoSection from "@/pages/paymentPage/components/userInfoSection/UserInfoSection"; import { usePaymentQuery } from "@hooks/api/query/usePaymentQuery"; -import { useSearchParams } from "react-router-dom"; +import { useParams } from "react-router-dom"; import PaymentButton from "./components/paymentButton/PaymentButton"; import { FormProvider, useForm } from "react-hook-form"; import Caption from "@components/caption/Caption"; const Payment = () => { - const [searchParams] = useSearchParams(); - const product = searchParams.get("product") ?? ""; + const { productId } = useParams(); + if (!productId) throw Error("존재하지 않는 productId 입니다."); - const { data } = usePaymentQuery(product); + const { data } = usePaymentQuery(productId); const methods = useForm({ mode: "onChange", @@ -47,7 +47,7 @@ const Payment = () => { - + diff --git a/src/pages/paymentPage/components/paymentButton/PaymentButton.tsx b/src/pages/paymentPage/components/paymentButton/PaymentButton.tsx index 6f968af7..b90473d5 100644 --- a/src/pages/paymentPage/components/paymentButton/PaymentButton.tsx +++ b/src/pages/paymentPage/components/paymentButton/PaymentButton.tsx @@ -2,14 +2,13 @@ import { useFormContext } from "react-hook-form"; import { usePaymentMutation } from "@hooks/api/mutation/usePaymentMutation"; import * as S from "./PaymentButton.style"; -import type { PaymentData } from "@type/payment"; interface PaymentButtonProps { productId: string; - payment: Pick; + price: number; } -const PaymentButton = ({ productId, payment }: PaymentButtonProps) => { +const PaymentButton = ({ productId, price }: PaymentButtonProps) => { const { handleSubmit, getValues, @@ -55,7 +54,7 @@ const PaymentButton = ({ productId, payment }: PaymentButtonProps) => { data-disabled={isValid ? null : ""} aria-label="결제하기" > - {payment.salePrice.toLocaleString("ko-KR")}원 결제하기 + {price.toLocaleString("ko-KR")}원 결제하기 ); }; diff --git a/src/pages/paymentSuccessPage/PaymentSuccess.tsx b/src/pages/paymentSuccessPage/PaymentSuccess.tsx index 93a52337..9f0667a0 100644 --- a/src/pages/paymentSuccessPage/PaymentSuccess.tsx +++ b/src/pages/paymentSuccessPage/PaymentSuccess.tsx @@ -1,4 +1,4 @@ -import { useSearchParams } from "react-router-dom"; +import { useParams } from "react-router-dom"; import { usePurchaseDetailQuery } from "@hooks/api/query/usePurchaseQuery"; import PaymentSuccessInfo from "@pages/paymentSuccessPage/components/PaymentSuccessInfo/PaymentSuccessInfo"; @@ -9,10 +9,10 @@ import CardItem from "@components/cardItem/CardItem"; import * as S from "./PaymentSuccess.style"; const PaymentSuccess = () => { - const [searchParams] = useSearchParams(); - const product = searchParams.get("product") ?? ""; + const { productId } = useParams(); + if (!productId) throw Error("존재하지 않는 productId 입니다."); - const { data } = usePurchaseDetailQuery(product); + const { data } = usePurchaseDetailQuery(productId); return ( @@ -63,7 +63,7 @@ const PaymentSuccess = () => { - + ); From 8c619257dedf64f0f657d590f45c29a352eaffa5 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:08:18 +0900 Subject: [PATCH 22/26] =?UTF-8?q?design:=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20fixed=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/toast/Toast.style.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/toast/Toast.style.ts b/src/components/toast/Toast.style.ts index da782af1..74c1b9a4 100644 --- a/src/components/toast/Toast.style.ts +++ b/src/components/toast/Toast.style.ts @@ -16,7 +16,7 @@ export const ToastContainer = styled(motion.div)<{ $isError: boolean }>` justify-content: center; align-items: center; - position: absolute; + position: fixed; left: 0; right: 0; top: 80px; From c32b047eaeda3df2217e8ff642661ea56d9daa59 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:09:00 +0900 Subject: [PATCH 23/26] =?UTF-8?q?fix:=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=EC=9A=94=EC=B2=AD=20=ED=9B=85=20throwOnError?= =?UTF-8?q?=EC=97=90=20=EC=A1=B0=EA=B1=B4=20=EA=B1=B8=EC=96=B4=EC=84=9C=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EB=8D=98=EC=A7=80=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/api/mutation/useValidateEmailMutation.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hooks/api/mutation/useValidateEmailMutation.ts b/src/hooks/api/mutation/useValidateEmailMutation.ts index 8bebda67..5d11f5db 100644 --- a/src/hooks/api/mutation/useValidateEmailMutation.ts +++ b/src/hooks/api/mutation/useValidateEmailMutation.ts @@ -1,10 +1,13 @@ import { postValidateEmail } from "@apis/fetchLogin"; import { useMutation } from "@tanstack/react-query"; +import { isAxiosError } from "axios"; export const useValidateEmailMutation = () => { const validateEmailMutation = useMutation({ mutationFn: ({ email }: { email: string }) => postValidateEmail(email), - throwOnError: true, + throwOnError: (error) => { + return !(isAxiosError(error) && error.response); + }, }); return validateEmailMutation; From 9dbbebef5fe4233fcb678f890029b517ab6796e4 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:09:20 +0900 Subject: [PATCH 24/26] =?UTF-8?q?design:=20=EC=B2=B4=ED=81=AC=EB=B0=95?= =?UTF-8?q?=EC=8A=A4=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/checkbox/Checkbox.style.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/checkbox/Checkbox.style.ts b/src/components/checkbox/Checkbox.style.ts index 81958ef4..b7b1d892 100644 --- a/src/components/checkbox/Checkbox.style.ts +++ b/src/components/checkbox/Checkbox.style.ts @@ -1,4 +1,4 @@ -import styled, { DefaultTheme } from "styled-components"; +import styled, { DefaultTheme, css } from "styled-components"; export interface CheckboxStyleProps { size?: "sm" | "md" | "lg"; @@ -117,11 +117,11 @@ export const StyledCheckbox = styled.span` `; const labelStyles = { - title: (theme: DefaultTheme) => ` + title: (theme: DefaultTheme) => css` color: ${theme.color.greyScale1}; } `, - caption: (theme: DefaultTheme) => ` + caption: (theme: DefaultTheme) => css` color: ${theme.color.greyScale3}; } `, @@ -140,8 +140,6 @@ export const LabelText = styled.span.withConfig({ ${({ theme }) => theme.typo.caption1} - ${({ variant, theme }) => variant && labelStyles[variant](theme)}; - margin-inline-start: 0.5rem; user-select: none; @@ -150,4 +148,6 @@ export const LabelText = styled.span.withConfig({ text-underline-offset: 2px; color: inherit; } + + ${({ variant, theme }) => variant && labelStyles[variant](theme)}; `; From 2e32aab8cd2ea49b3d562b633ec147e834aa7ea1 Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:09:44 +0900 Subject: [PATCH 25/26] =?UTF-8?q?feat:=20=EC=83=81=EC=84=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EA=B5=AC=EB=A7=A4=EC=97=B0=EA=B2=B0,=20?= =?UTF-8?q?=ED=97=A4=EB=8D=94=20=EB=92=A4=EB=A1=9C=EA=B0=80=EA=B8=B0=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/roomDetailPage/RoomDetail.tsx | 32 ++++++++++------- .../components/roomHeader/RoomHeader.style.ts | 13 ++++--- .../components/roomHeader/RoomHeader.tsx | 13 +++++-- .../components/roomInfo/RoomInfo.tsx | 11 +++--- .../components/roomNavBar/RoomNavBar.style.ts | 3 +- .../components/roomNavBar/RoomNavBar.tsx | 35 +++++++++++++++---- 6 files changed, 72 insertions(+), 35 deletions(-) diff --git a/src/pages/roomDetailPage/RoomDetail.tsx b/src/pages/roomDetailPage/RoomDetail.tsx index ffdc7931..de7b00f0 100644 --- a/src/pages/roomDetailPage/RoomDetail.tsx +++ b/src/pages/roomDetailPage/RoomDetail.tsx @@ -1,38 +1,44 @@ -import { getRoom } from "@apis/fetchRoom"; - import Carousel from "@components/carousel/Carousel"; import RoomHeader from "@pages/roomDetailPage/components/roomHeader/RoomHeader"; import RoomInfo from "@pages/roomDetailPage/components/roomInfo/RoomInfo"; import RoomNavBar from "@pages/roomDetailPage/components/roomNavBar/RoomNavBar"; -import { useSuspenseQuery } from "@tanstack/react-query"; -import type { RoomData } from "@type/room"; -import type { AxiosError } from "axios"; + +import useToastConfig from "@hooks/common/useToastConfig"; +import { useRoomQuery } from "@hooks/api/useRoomQuery"; import { useParams } from "react-router-dom"; import * as S from "./RoomDetail.style"; +import { useEffect } from "react"; const RoomDetail = () => { const { roomId } = useParams(); if (!roomId) throw new Error("존재하지 않는 roomId 입니다."); - const { data } = useSuspenseQuery({ - queryKey: ["room"], - queryFn: () => getRoom(roomId), - }); + const { data } = useRoomQuery(roomId); + const { rawData, discountRate } = data; + + const { handleToast } = useToastConfig(); + + useEffect(() => { + if (rawData.isSeller) { + handleToast(false, ["내가 판매 중인 상품입니다"]); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [rawData.isSeller]); return ( - + - - + + ); }; diff --git a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts index a86be054..5471ab90 100644 --- a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts +++ b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.style.ts @@ -8,22 +8,25 @@ export const ScrollObserver = styled.div` `; export const HeaderContainer = styled.header<{ $visible: boolean }>` - display: flex; - align-items: center; position: fixed; top: 0; + + display: flex; + align-items: center; width: 100%; max-width: 768px; height: 56px; - z-index: 2; + background-color: ${({ $visible, theme }) => - $visible ? "unset" : theme.color.white}; + $visible ? "transparent" : theme.color.white}; border-bottom: ${({ $visible, theme }) => - $visible ? "none" : `1px solid ${theme.color.greyScale7}`}; + $visible ? "0" : `1px solid ${theme.color.greyScale7}`}; transition: border-bottom, background-color 0.5s ease-in; + + z-index: 2; `; export const Wrapper = styled.div` diff --git a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.tsx b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.tsx index 02413f20..7bea78ee 100644 --- a/src/pages/roomDetailPage/components/roomHeader/RoomHeader.tsx +++ b/src/pages/roomDetailPage/components/roomHeader/RoomHeader.tsx @@ -1,5 +1,7 @@ import useIsVisible from "@hooks/common/useIsVisible"; + import * as S from "./RoomHeader.style"; +import { useNavigate } from "react-router-dom"; interface RoomHeaderProps { title: string; @@ -11,15 +13,22 @@ const RoomHeader = ({ title }: RoomHeaderProps) => { rootMargin: "0px", threshold: 1.0, }, - initialVisible: false, + initialVisible: true, }); + const navigate = useNavigate(); + return ( <>
-
diff --git a/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx b/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx index 03cb040f..199e38e5 100644 --- a/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx +++ b/src/pages/roomDetailPage/components/roomInfo/RoomInfo.tsx @@ -1,19 +1,18 @@ import RoomThemeOption from "@pages/roomDetailPage/components/roomThemeOption/RoomThemeOption"; -import * as S from "@pages/roomDetailPage/RoomDetail.style"; import type { RoomData } from "@type/room"; -import { calculateDiscount } from "@utils/calculator"; import { formatDate } from "@utils/dateFormatter"; import IconBed from "@assets/icons/ic_bed.svg?react"; import IconCaretRight from "@assets/icons/ic_caret_right.svg?react"; import IconUser from "@assets/icons/ic_users.svg?react"; +import * as S from "@pages/roomDetailPage/RoomDetail.style"; + interface RoomInfoProps { room: RoomData; + discount: string; } -const RoomInfo = ({ room }: RoomInfoProps) => { - const discountRate = calculateDiscount(room.originalPrice, room.sellingPrice); - +const RoomInfo = ({ room, discount }: RoomInfoProps) => { const checkInDate = formatDate(room.checkIn); const checkOutDate = formatDate(room.checkOut); return ( @@ -35,7 +34,7 @@ const RoomInfo = ({ room }: RoomInfoProps) => { 판매가 - {discountRate}% + {discount}% {room.sellingPrice.toLocaleString()}원 diff --git a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts index 6d56ed74..b895cc6b 100644 --- a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts +++ b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.style.ts @@ -33,7 +33,6 @@ export const Row2 = styled(Flex)` gap: 0.5rem; `; -// FIXME: Button 컴포넌트 만들기 export const Button = styled.button<{ $status: boolean }>` ${({ theme }) => theme.typo.button2} padding: 0.7rem 3rem; @@ -41,7 +40,7 @@ export const Button = styled.button<{ $status: boolean }>` border-radius: 8px; background-color: ${({ $status, theme }) => $status ? theme.color.percentOrange : theme.color.greyScale5}; - transition: background-color 0.5s ease-in; + transition: background-color 0.2s ease-in; &:hover { background-color: ${({ $status, theme }) => diff --git a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx index 831d2dc5..59ddd833 100644 --- a/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx +++ b/src/pages/roomDetailPage/components/roomNavBar/RoomNavBar.tsx @@ -1,14 +1,30 @@ -import { RoomNavBarData } from "@type/room"; -import { calculateDiscount } from "@utils/calculator"; +import { useNavigate } from "react-router-dom"; +import type { RoomNavBarData } from "@type/room"; +import { PATH } from "@constants/path"; +import useToastConfig from "@hooks/common/useToastConfig"; + import * as S from "./RoomNavBar.style"; interface RoomNavBarProps { room: RoomNavBarData; + roomId: string; + discount: string; } -const RoomNavBar = ({ room }: RoomNavBarProps) => { - // FIXME: 패칭 후 가공단계에서 할인율 계산 - const discountRate = calculateDiscount(room.originalPrice, room.sellingPrice); +const RoomNavBar = ({ room, roomId, discount }: RoomNavBarProps) => { + const navigate = useNavigate(); + const { handleToast } = useToastConfig(); + + const handlePurchaseClick = () => { + if (room.isSeller) { + handleToast(true, [<>내가 판매하는 상품은 구매가 불가합니다]); + return; + } else if (!room.saleStatus) { + return; + } + + navigate(`${PATH.PAYMENT}/${roomId}`); + }; return ( @@ -18,14 +34,19 @@ const RoomNavBar = ({ room }: RoomNavBarProps) => { - {discountRate}% + {discount}% {room.sellingPrice.toLocaleString()}원 - + 구매하기
From 82f2c6effc57c99fcfc41d48abcccfb168b47c7c Mon Sep 17 00:00:00 2001 From: Park Nayoung <139189221+im-na0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:10:32 +0900 Subject: [PATCH 26/26] =?UTF-8?q?fix:=20useIsVisible=20=ED=9B=85=EC=97=90?= =?UTF-8?q?=EC=84=9C=20isVisible=EC=83=81=ED=83=9C=EA=B0=80=20=EB=B0=94?= =?UTF-8?q?=EB=80=94=20=EB=95=8C=EB=A7=8C=20observer=EA=B0=80=20=ED=99=9C?= =?UTF-8?q?=EC=84=B1=ED=99=94=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/common/useIsVisible.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hooks/common/useIsVisible.ts b/src/hooks/common/useIsVisible.ts index f0d6a7a5..582ebfb9 100644 --- a/src/hooks/common/useIsVisible.ts +++ b/src/hooks/common/useIsVisible.ts @@ -17,12 +17,13 @@ const useIsVisible = (props: UseIsVisibleProps): UseIsVisibleReturnType => { useEffect(() => { const observer = new IntersectionObserver(([entry]) => { - setIsVisible(entry.isIntersecting); + if (entry.isIntersecting !== isVisible) { + setIsVisible(entry.isIntersecting); + } }, options); if (visibleRef) { observer.observe(visibleRef); - return; } return () => { @@ -30,7 +31,7 @@ const useIsVisible = (props: UseIsVisibleProps): UseIsVisibleReturnType => { observer.unobserve(visibleRef); } }; - }, [options, visibleRef]); + }, [options, visibleRef, isVisible]); const setRefCallback: RefCallback = (node) => { setVisibleRef(node);