182 lines
5.0 KiB
TypeScript
182 lines
5.0 KiB
TypeScript
import { ApiError, SinglePayment, useApi } from "@/api";
|
|
import { User } from "@/api/resources/User";
|
|
import { AuthToken } from "@/api/types";
|
|
import { productUrls } from "@/data/products";
|
|
import routes from "@/routes";
|
|
import { getZodiacSignByDate } from "@/services/zodiac-sign";
|
|
import { selectors } from "@/store";
|
|
import { useCallback, useMemo, useState } from "react";
|
|
import { useSelector } from "react-redux";
|
|
import { useNavigate } from "react-router-dom";
|
|
|
|
interface ICreateSinglePaymentProps {
|
|
user: User;
|
|
token: AuthToken;
|
|
targetProductKey: string;
|
|
returnUrl: string;
|
|
}
|
|
|
|
interface IErrorSinglePayment {
|
|
error?: string;
|
|
}
|
|
|
|
export const useSinglePayment = () => {
|
|
const api = useApi();
|
|
const navigate = useNavigate();
|
|
const [paymentIntent, setPaymentIntent] =
|
|
useState<SinglePayment.ResponsePost>();
|
|
const [product, setProduct] = useState<SinglePayment.ResponseGet>();
|
|
const [error, setError] = useState<IErrorSinglePayment>(
|
|
{} as IErrorSinglePayment
|
|
);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const { gender } = useSelector(selectors.selectQuestionnaire);
|
|
const birthday = useSelector(selectors.selectBirthday);
|
|
|
|
const getCurrentProduct = useCallback(
|
|
async (token: AuthToken, targetProductKey: string) => {
|
|
const productsSinglePayment = await api.getSinglePaymentProducts({
|
|
token,
|
|
});
|
|
const currentProduct = productsSinglePayment.find(
|
|
(product) => product.key === targetProductKey
|
|
);
|
|
return currentProduct;
|
|
},
|
|
[api]
|
|
);
|
|
|
|
const handlerPaymentIntentResult = useCallback(
|
|
(paymentIntent: SinglePayment.ResponsePost, type: string) => {
|
|
if (!("payment" in paymentIntent)) return;
|
|
let status = "failed";
|
|
if (paymentIntent.payment.status === "paid") {
|
|
status = "succeeded";
|
|
}
|
|
return navigate(
|
|
`${routes.client.paymentResult()}?redirect_status=${status}&redirect_type=${type}`
|
|
);
|
|
},
|
|
[navigate]
|
|
);
|
|
|
|
const checkProductPurchased = useCallback(
|
|
async (email: string, productKey: string, token: AuthToken) => {
|
|
try {
|
|
const purchased = await api.checkProductPurchased({
|
|
email,
|
|
productKey,
|
|
token,
|
|
});
|
|
|
|
if ("active" in purchased && purchased.active) {
|
|
return true;
|
|
}
|
|
return false;
|
|
} catch (error) {
|
|
console.error(error);
|
|
return false;
|
|
}
|
|
},
|
|
[api]
|
|
);
|
|
|
|
const createSinglePayment = useCallback(
|
|
async ({
|
|
user,
|
|
token,
|
|
targetProductKey,
|
|
returnUrl,
|
|
}: ICreateSinglePaymentProps) => {
|
|
setIsLoading(true);
|
|
const product = await getCurrentProduct(token, targetProductKey);
|
|
if (!product) {
|
|
setError({ error: "Product not found" });
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
setProduct(product);
|
|
const isPurchased = await checkProductPurchased(
|
|
user?.email || "",
|
|
targetProductKey,
|
|
token
|
|
);
|
|
if (isPurchased && productUrls[targetProductKey]?.length) {
|
|
return navigate(productUrls[targetProductKey]);
|
|
}
|
|
|
|
let _gender = "male";
|
|
if (gender.length) {
|
|
_gender = gender;
|
|
}
|
|
if (user.profile.gender?.length) {
|
|
_gender = user.profile.gender;
|
|
}
|
|
const paymentIntent = await api.createSinglePayment({
|
|
token,
|
|
data: {
|
|
user: {
|
|
id: `${user?.id}`,
|
|
email: user?.email,
|
|
name: user.username || "",
|
|
sign:
|
|
user?.profile?.sign?.sign ||
|
|
getZodiacSignByDate(user.profile.birthday || birthday || ""),
|
|
age: user?.profile?.age?.years || 1,
|
|
gender: _gender,
|
|
},
|
|
partner: {
|
|
sign: null,
|
|
age: null,
|
|
},
|
|
paymentInfo: {
|
|
productId: product?.productId || "",
|
|
key: product?.key || "",
|
|
},
|
|
return_url: returnUrl,
|
|
},
|
|
}).catch((error: ApiError<SinglePayment.ResponsePost>) => {
|
|
if (error.responseData && "message" in error.responseData) {
|
|
setError({ error: error.responseData.message });
|
|
} else {
|
|
setError({ error: error.message });
|
|
}
|
|
setIsLoading(false);
|
|
return;
|
|
});
|
|
if (typeof paymentIntent !== "object") {
|
|
return;
|
|
}
|
|
if ("message" in paymentIntent) {
|
|
setError({ error: paymentIntent.message });
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
handlerPaymentIntentResult(paymentIntent, targetProductKey);
|
|
setPaymentIntent(paymentIntent);
|
|
setIsLoading(false);
|
|
return paymentIntent;
|
|
},
|
|
[
|
|
api,
|
|
birthday,
|
|
checkProductPurchased,
|
|
gender,
|
|
getCurrentProduct,
|
|
handlerPaymentIntentResult,
|
|
navigate,
|
|
]
|
|
);
|
|
|
|
return useMemo(
|
|
() => ({
|
|
product,
|
|
paymentIntent,
|
|
createSinglePayment,
|
|
isLoading,
|
|
error,
|
|
}),
|
|
[product, paymentIntent, createSinglePayment, isLoading, error]
|
|
);
|
|
};
|