181 lines
6.3 KiB
TypeScript
181 lines
6.3 KiB
TypeScript
import Title from "@/components/Title";
|
|
import styles from "./styles.module.css";
|
|
import { unlimitedReadings } from "@/data/additionalPurchases";
|
|
import FooterButton from "../../components/FooterButton";
|
|
import { useNavigate } from "react-router-dom";
|
|
import Slider from "react-slick";
|
|
import FirstSlide from "../../components/FirstSlide";
|
|
import SliderNextArrow from "../../components/SliderNextArrow";
|
|
import SliderPrevArrow from "../../components/SliderPrevArrow";
|
|
import routes from "@/routes";
|
|
import PaymentAddress from "../../components/PaymentAddress";
|
|
import { useAuth } from "@/auth";
|
|
import { SinglePayment, useApi, useApiCall } from "@/api";
|
|
import { useSelector } from "react-redux";
|
|
import { selectors } from "@/store";
|
|
import { useCallback, useState } from "react";
|
|
import { createSinglePayment } from "@/services/singlePayment";
|
|
import Loader, { LoaderColor } from "@/components/Loader";
|
|
import { ResponsePost } from "@/api/resources/SinglePayment";
|
|
import Modal from "@/components/Modal";
|
|
import { getPriceCentsToDollars } from "@/services/price";
|
|
import PaymentForm from "@/components/pages/SinglePaymentPage/PaymentForm";
|
|
import { useTranslations } from "@/hooks/translations";
|
|
import { addCurrency, ELocalesPlacement } from "@/locales";
|
|
|
|
const sliderSettings = {
|
|
dots: false,
|
|
infinite: false,
|
|
speed: 500,
|
|
slidesToShow: 1,
|
|
slidesToScroll: 1,
|
|
className: styles["slider-container"],
|
|
nextArrow: <SliderNextArrow />,
|
|
prevArrow: <SliderPrevArrow />,
|
|
};
|
|
|
|
function UnlimitedReadingsPage() {
|
|
const navigate = useNavigate();
|
|
const { translate } = useTranslations(ELocalesPlacement.V1);
|
|
const { user: userFromStore } = useAuth();
|
|
const api = useApi();
|
|
const tokenFromStore = useSelector(selectors.selectToken);
|
|
const currency = useSelector(selectors.selectCurrency);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [paymentIntent, setPaymentIntent] = useState<ResponsePost | null>(null);
|
|
const [isError, setIsError] = useState(false);
|
|
const returnUrl = `${window.location.protocol}//${
|
|
window.location.host
|
|
}${routes.client.addConsultation()}`;
|
|
|
|
const loadData = useCallback(async () => {
|
|
return await api.getSinglePaymentProducts({ token: tokenFromStore });
|
|
}, [api, tokenFromStore]);
|
|
|
|
const { data: products, isPending: isPendingProducts } =
|
|
useApiCall<SinglePayment.ResponseGet[]>(loadData);
|
|
|
|
const currentProduct = products?.find(
|
|
(product) => product.key === "main.unlimited.readings"
|
|
);
|
|
|
|
const handleClick = async () => {
|
|
try {
|
|
if (!userFromStore || !currentProduct) return;
|
|
setIsLoading(true);
|
|
const { _id, key } = currentProduct;
|
|
const paymentInfo = {
|
|
productId: _id,
|
|
key,
|
|
};
|
|
const paymentIntent = await createSinglePayment(
|
|
userFromStore,
|
|
paymentInfo,
|
|
tokenFromStore,
|
|
userFromStore.email,
|
|
userFromStore.profile.full_name,
|
|
userFromStore.profile.birthday,
|
|
returnUrl,
|
|
api
|
|
);
|
|
setPaymentIntent(paymentIntent);
|
|
if ("payment" in paymentIntent) {
|
|
if (paymentIntent.payment.status === "paid")
|
|
return navigate(routes.client.addConsultation());
|
|
return setIsError(true);
|
|
}
|
|
} catch (error) {
|
|
setIsError(true);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleClickSkip = () => {
|
|
navigate(routes.client.addConsultation());
|
|
};
|
|
|
|
return (
|
|
<div className={styles.container}>
|
|
{!isLoading &&
|
|
paymentIntent &&
|
|
"paymentIntent" in paymentIntent &&
|
|
!!tokenFromStore.length && (
|
|
<>
|
|
<Modal
|
|
open={!!paymentIntent}
|
|
onClose={() => setPaymentIntent(null)}
|
|
>
|
|
<Title variant="h1" className={styles["modal-title"]}>
|
|
{getPriceCentsToDollars(currentProduct?.price || 0)}$
|
|
</Title>
|
|
<PaymentForm
|
|
stripePublicKey={paymentIntent.paymentIntent.data.public_key}
|
|
clientSecret={paymentIntent.paymentIntent.data.client_secret}
|
|
returnUrl={returnUrl}
|
|
/>
|
|
</Modal>
|
|
</>
|
|
)}
|
|
{!currentProduct && (
|
|
<Loader className={styles.loader} color={LoaderColor.Black} />
|
|
)}
|
|
{!!currentProduct?.price && (
|
|
<>
|
|
<Slider {...sliderSettings}>
|
|
<FirstSlide price={currentProduct?.price || 0} />
|
|
<div className={styles.slider}>
|
|
<img src="/premium_intro_2.webp" alt="Premium Intro" />
|
|
<img src="/premium_intro_3.webp" alt="Premium Intro" />
|
|
</div>
|
|
<div className={styles.slider}>
|
|
<img src="/premium_intro_4.webp" alt="Premium Intro" />
|
|
<img src="/premium_intro_5.webp" alt="Premium Intro" />
|
|
</div>
|
|
</Slider>
|
|
<Title variant="h2" className={styles.title}>
|
|
{translate("/unlimited-readings.title")}
|
|
</Title>
|
|
<ul className={styles.list}>
|
|
{unlimitedReadings.map(({ title, icon }, index) => (
|
|
<li className={styles.item} key={index}>
|
|
<span
|
|
className={styles.image}
|
|
style={{ backgroundImage: `url(${icon})` }}
|
|
/>
|
|
<span className={styles.text}>{translate(title)}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
{isError && <p className={styles.error}>{translate("went_wrong")}</p>}
|
|
<FooterButton
|
|
onClick={handleClick}
|
|
onClickSkip={handleClickSkip}
|
|
classNameContainer={styles["buttons-container"]}
|
|
classNameButton={styles.button}
|
|
classNameSkip={styles.skip}
|
|
disabled={isPendingProducts || isLoading}
|
|
>
|
|
{isPendingProducts || isLoading ? (
|
|
<Loader color={LoaderColor.White} />
|
|
) : (
|
|
translate("/unlimited-readings.add_unlimited_readings")
|
|
)}
|
|
</FooterButton>
|
|
<p className={styles.policy}>
|
|
{translate("/unlimited-readings.description", {
|
|
price: addCurrency(
|
|
((currentProduct?.price || 0) / 100).toFixed(2),
|
|
currency
|
|
),
|
|
})}
|
|
</p>
|
|
<PaymentAddress />
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default UnlimitedReadingsPage;
|