Skip to content

Commit

Permalink
Merge pull request #189 from SCBJ-7/feature/#188-refactor-payment
Browse files Browse the repository at this point in the history
[#188] 결제 취소시 모달 띄우기
  • Loading branch information
im-na0 authored Jan 25, 2024
2 parents aaa1818 + 2647a67 commit d45a336
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 39 deletions.
36 changes: 22 additions & 14 deletions src/apis/fetchPayment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ export const getStock = async (productId: string): Promise<StockData> => {
return data.data;
};

export const getPayment = async (productId: string): Promise<PaymentData> => {
const { data } = await axiosInstance.get<ResponseData<PaymentData>>(
END_POINTS.PAYMENT(productId),
);
return data.data;
};

export interface PaymentRequestProps {
productId: string;
paymentType: string;
Expand All @@ -31,6 +24,18 @@ export interface PaymentRequestProps {
thirdPartySharing: boolean;
}

export interface PaymentSuccessProps {
paymentType: string;
pgToken: Nullable<string>;
}

export const getPayment = async (productId: string): Promise<PaymentData> => {
const { data } = await axiosInstance.get<ResponseData<PaymentData>>(
END_POINTS.PAYMENT(productId),
);
return data.data;
};

export const postPayment = async (
paymentRequest: PaymentRequestProps,
): Promise<PaymentRequestData> => {
Expand Down Expand Up @@ -63,20 +68,23 @@ export const postPayment = async (
return data.data;
};

export interface PaymentSuccessProps {
paymentType: string;
pgToken: Nullable<string>;
}

export const getPaymentSuccess = async ({
paymentType,
pgToken,
}: PaymentSuccessProps): Promise<PaymentData | null> => {
}: PaymentSuccessProps) => {
if (!pgToken) return null;

const { data } = await axiosInstance.get<ResponseData<PaymentData>>(
const { data } = await axiosInstance.get(
END_POINTS.PAYMENT_SUCCESS(paymentType, pgToken),
);
console.log(data);
return data.data;
};

export const getPaymentCancel = async (paymentType: string) => {
const { data } = await axiosInstance.get(
END_POINTS.PAYMENT_CANCEL(paymentType),
);
console.log(data);
return data.data;
};
2 changes: 2 additions & 0 deletions src/constants/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export const END_POINTS = {
`/v1/products/${productId}/payments?paymentType=${paymentType}`,
PAYMENT_SUCCESS: (paymentType: string, pgToken: string) =>
`/v1/products/pay-success?paymentType=${paymentType}&pg_token=${pgToken}`,
PAYMENT_CANCEL: (paymentType: string) =>
`/v1/products/pay-cancel?paymentType=${paymentType}`,
STOCK: (productId: string) => `/v1/products/${productId}/stock`,
NEW_TOKEN: "/v1/token/refresh",
} as const;
Expand Down
8 changes: 8 additions & 0 deletions src/constants/caption.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const paymentCaptions = {
text1:
"일부 상품의 경우, 결제완료 후 예약 확정까지 최대 1시간이 소요될 수 있습니다.",
text2:
"숙소 사정에 의해 예약 확정 불가 시, 자동 취소처리 및 전액환불 처리됩니다. <예약 확정 대기> 상태에서도 취소요청이 가능하나, 상품별 취소 정책에 따라 취소수수료가 부과되거나 환불이 불가할 수 있습니다.",
text3:
"(주)야놀자는 통신판매중개업자로서, 통신판매의 당사자가 아니라는 사실을 고지하며 상품의 결제, 이용 및 환불 등과 관련한 의무와 책임은 각 판매자에게 있습니다.",
};
18 changes: 16 additions & 2 deletions src/hooks/api/query/usePaymentQuery.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { getPayment, getPaymentSuccess } from "@apis/fetchPayment";
import {
getPayment,
getPaymentCancel,
getPaymentSuccess,
} from "@apis/fetchPayment";
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
import type { PaymentData } from "@type/payment";
import type { Nullable } from "@type/nullable";
Expand All @@ -24,8 +28,18 @@ export const usePaymentSuccessQuery = ({
const paymentSuccessQuery = useQuery({
queryKey: ["payment"],
queryFn: async () => await getPaymentSuccess({ paymentType, pgToken }),
enabled: !!pgToken,
enabled: false,
});

return paymentSuccessQuery;
};

export const usePaymentCancelQuery = (paymentType: string) => {
const paymentCancelQuery = useQuery({
queryKey: ["payment"],
queryFn: async () => await getPaymentCancel(paymentType),
enabled: false,
});

return paymentCancelQuery;
};
12 changes: 6 additions & 6 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ 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";
// import { worker } from "./mocks/broswer";
import { router } from "./routes/router";
import { GlobalStyle } from "./styles/globalStyle";
import { theme } from "./styles/theme";
Expand All @@ -16,11 +16,11 @@ const queryClient = new QueryClient({
},
});

if (process.env.NODE_ENV === "development") {
worker.start({
onUnhandledRequest: "bypass",
});
}
// if (process.env.NODE_ENV === "development") {
// worker.start({
// onUnhandledRequest: "bypass",
// });
// }

ReactDOM.createRoot(document.getElementById("root")!).render(
<QueryClientProvider client={queryClient}>
Expand Down
52 changes: 38 additions & 14 deletions src/pages/paymentPage/Payment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,30 @@ import PaymentMethodSection from "@/pages/paymentPage/components/paymentMethodSe
import TermsAgreementSection from "@/pages/paymentPage/components/termsAgreementSection/TermsAgreementSection";
import UserInfoSection from "@/pages/paymentPage/components/userInfoSection/UserInfoSection";
import {
usePaymentCancelQuery,
usePaymentQuery,
usePaymentSuccessQuery,
} from "@hooks/api/query/usePaymentQuery";
import { useNavigate, useParams } from "react-router-dom";
import PaymentButton from "./components/paymentButton/PaymentButton";

import { useLocation } from "react-router-dom";
import { FormProvider, useForm } from "react-hook-form";
import Caption from "@components/caption/Caption";
import Modal from "@components/modal/Modal";
import { useEffect, useState } from "react";
import { isAxiosError } from "axios";
import { paymentCaptions } from "@constants/caption";

interface PaymentProps {
action: "default" | "cancel" | "ready";
}

const Payment = () => {
const Payment = ({ action }: PaymentProps) => {
const navigate = useNavigate();
const location = useLocation();
const { productId } = useParams();
if (!productId) throw Error("존재하지 않는 productId 입니다.");

console.log(productId);

const { data } = usePaymentQuery(productId);

const searchParams = new URLSearchParams(location.search);
Expand All @@ -31,19 +36,42 @@ const Payment = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const [errorMessage, setErrorMessage] = useState("");

const { isSuccess, isError, error } = usePaymentSuccessQuery({
const {
isSuccess,
isError,
error,
refetch: paymentSuccessQuery,
} = usePaymentSuccessQuery({
paymentType,
pgToken,
});

const { refetch: paymentCancelQuery } = usePaymentCancelQuery(paymentType);

useEffect(() => {
if (action === "ready") {
paymentSuccessQuery();
}

if (action === "cancel") {
paymentCancelQuery();
setErrorMessage("결제가 취소되었습니다.");
setIsModalOpen(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [action]);

useEffect(() => {
if (isSuccess) {
navigate(`/payment/${productId}/success`);
}

if (isError && isAxiosError(error)) {
console.error(error);
setErrorMessage(error.response?.data.message || "오류가 발생했습니다.");
if (error.response?.status === 409) {
setErrorMessage("이미 판매완료된 상품입니다.");
} else {
setErrorMessage(error.response?.data.message || "오류가 발생했습니다.");
}
setIsModalOpen(true);
}
}, [isSuccess, isError, error, navigate, productId]);
Expand Down Expand Up @@ -77,13 +105,9 @@ const Payment = () => {
<TermsAgreementSection />
</S.Section>
<S.CaptionWrapper>
<Caption text="일부 상품의 경우, 결제완료 후 예약 확정까지 최대 1시간이 소요될 수 있습니다.">
{
"숙소 사정에 의해 예약 확정 불가 시, 자동 취소처리 및 전액환불 처리됩니다. <예약 확정 대기> 상태에서도 취소요청이 가능하나, 상품별 취소 정책에 따라 취소수수료가 부과되거나 환불이 불가할 수 있습니다."
}
{
"(주)야놀자는 통신판매중개업자로서, 통신판매의 당사자가 아니라는 사실을 고지하며 상품의 결제, 이용 및 환불 등과 관련한 의무와 책임은 각 판매자에게 있습니다."
}
<Caption text={paymentCaptions.text1}>
{paymentCaptions.text2}
{paymentCaptions.text3}
</Caption>
</S.CaptionWrapper>
<S.BottomWrapper>
Expand Down
10 changes: 7 additions & 3 deletions src/routes/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -190,22 +190,26 @@ export const router = createBrowserRouter([
element: (
<LocalErrorBoundary>
<Suspense fallback={<Loading />}>
<Payment />
<Outlet />
</Suspense>
</LocalErrorBoundary>
),
children: [
{
path: "",
element: <Payment />,
element: <Payment action="default" />,
},
{
path: "success",
element: <PaymentSuccess />,
},
{
path: "ready",
element: <Payment />,
element: <Payment action="ready" />,
},
{
path: "cancel",
element: <Payment action="cancel" />,
},
],
},
Expand Down

0 comments on commit d45a336

Please sign in to comment.