203 lines
6.4 KiB
TypeScript
203 lines
6.4 KiB
TypeScript
import Title from "@/components/Title";
|
|
import styles from "./styles.module.css";
|
|
import PaymentMethodsChoice from "../pages/TrialPayment/components/PaymentMethodsChoice";
|
|
import { useEffect, useMemo, useState } from "react";
|
|
import { EPaymentMethod, paymentMethods } from "@/data/paymentMethods";
|
|
import { Elements } from "@stripe/react-stripe-js";
|
|
import CheckoutForm from "@/components/PaymentPage/methods/CheckoutForm";
|
|
import { AvailablePaymentMethods, Stripe, loadStripe } from "@stripe/stripe-js";
|
|
import { useSelector } from "react-redux";
|
|
import { selectors } from "@/store";
|
|
import Loader from "@/components/Loader";
|
|
import SecurityPayments from "../pages/TrialPayment/components/SecurityPayments";
|
|
import { EPlacementKeys, IPaywallProduct } from "@/api/resources/Paywall";
|
|
import { usePaywall } from "@/hooks/paywall/usePaywall";
|
|
import { useMakePayment } from "@/hooks/payment/useMakePayment";
|
|
import ExpressCheckoutStripe from "@/components/PaymentPage/methods/ExpressCheckoutStripe";
|
|
import routes from "@/routes";
|
|
import { useNavigate } from "react-router-dom";
|
|
|
|
interface IPaymentModalProps {
|
|
activeProduct?: IPaywallProduct;
|
|
noTrial?: boolean;
|
|
returnUrl?: string;
|
|
placementKey: EPlacementKeys;
|
|
}
|
|
|
|
const getPrice = (product: IPaywallProduct | null) => {
|
|
if (!product) {
|
|
return 0;
|
|
}
|
|
return (product.trialPrice === 100 ? 99 : product.trialPrice || 0) / 100;
|
|
};
|
|
|
|
function PaymentModal({
|
|
activeProduct,
|
|
noTrial,
|
|
returnUrl,
|
|
placementKey,
|
|
}: IPaymentModalProps) {
|
|
const navigate = useNavigate();
|
|
const [stripePromise, setStripePromise] =
|
|
useState<Promise<Stripe | null> | null>(null);
|
|
|
|
const { products, placementId, paywallId } = usePaywall({
|
|
placementKey,
|
|
});
|
|
const activeProductFromStore = useSelector(selectors.selectActiveProduct);
|
|
|
|
const _activeProduct = activeProduct ? activeProduct : activeProductFromStore;
|
|
const {
|
|
paymentIntentId,
|
|
clientSecret,
|
|
returnUrl: checkoutUrl,
|
|
paymentType,
|
|
publicKey,
|
|
isLoading: isLoadingPayment,
|
|
error,
|
|
} = useMakePayment({
|
|
productId: _activeProduct?._id || "",
|
|
placementId,
|
|
paywallId,
|
|
returnPaidUrl: returnUrl,
|
|
});
|
|
|
|
const [availableMethods, setAvailableMethods] = useState<
|
|
AvailablePaymentMethods | undefined
|
|
>();
|
|
|
|
const [isLoadingExpressCheckout, setIsLoadingExpressCheckout] =
|
|
useState(true);
|
|
|
|
const isLoading = useMemo(() => {
|
|
return isLoadingPayment || isLoadingExpressCheckout;
|
|
}, [isLoadingPayment, isLoadingExpressCheckout]);
|
|
|
|
if (checkoutUrl?.length) {
|
|
window.location.href = checkoutUrl;
|
|
}
|
|
|
|
const paymentMethodsButtons = useMemo(() => {
|
|
return paymentMethods(availableMethods || null);
|
|
}, [availableMethods]);
|
|
|
|
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState(
|
|
paymentMethodsButtons[0].id
|
|
);
|
|
|
|
const onSelectPaymentMethod = (method: EPaymentMethod) => {
|
|
setSelectedPaymentMethod(method);
|
|
};
|
|
|
|
useEffect(() => {
|
|
(async () => {
|
|
if (!products?.length || !publicKey) return;
|
|
setStripePromise(loadStripe(publicKey));
|
|
const isActiveProduct = products.find(
|
|
(product) => product._id === _activeProduct?._id
|
|
);
|
|
if (!_activeProduct || !isActiveProduct) {
|
|
navigate(routes.client.trialChoice());
|
|
}
|
|
})();
|
|
}, [_activeProduct, navigate, products, publicKey]);
|
|
|
|
const onAvailableExpressCheckout = (
|
|
isAvailable: boolean,
|
|
availableMethods: AvailablePaymentMethods | undefined
|
|
) => {
|
|
if (isAvailable && availableMethods) {
|
|
setAvailableMethods(availableMethods);
|
|
return setSelectedPaymentMethod(EPaymentMethod.PAYMENT_BUTTONS);
|
|
}
|
|
return setAvailableMethods(undefined);
|
|
};
|
|
|
|
if (error?.length) {
|
|
return (
|
|
<div className={styles["payment-modal"]}>
|
|
<Title variant="h3" className={styles.title}>
|
|
Something went wrong
|
|
</Title>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{isLoading && (
|
|
<div className={styles["payment-modal"]}>
|
|
<div className={styles["payment-loader"]}>
|
|
<Loader />
|
|
</div>
|
|
</div>
|
|
)}
|
|
<div
|
|
className={`${styles["payment-modal"]} ${isLoading ? styles.hide : ""}`}
|
|
>
|
|
<Title variant="h3" className={styles.title}>
|
|
Choose payment method
|
|
</Title>
|
|
<PaymentMethodsChoice
|
|
paymentMethods={paymentMethodsButtons}
|
|
selectedPaymentMethod={selectedPaymentMethod}
|
|
onSelectPaymentMethod={onSelectPaymentMethod}
|
|
/>
|
|
{_activeProduct && (
|
|
<div>
|
|
{!noTrial && (
|
|
<>
|
|
<p className={styles["sub-plan-description"]}>
|
|
You will be charged only{" "}
|
|
<b>${getPrice(_activeProduct)} for your 3-day trial.</b>
|
|
</p>
|
|
<p className={styles["sub-plan-description"]}>
|
|
We`ll <b>email you a reminder</b> before your trial period
|
|
ends.
|
|
</p>
|
|
</>
|
|
)}
|
|
|
|
<p className={styles["sub-plan-description"]}>
|
|
Cancel anytime. The charge will appear on your bill as witapps.
|
|
</p>
|
|
</div>
|
|
)}
|
|
<div className={styles["payment-method-container"]}>
|
|
{stripePromise && clientSecret && (
|
|
<>
|
|
<Elements stripe={stripePromise} options={{ clientSecret }}>
|
|
<ExpressCheckoutStripe
|
|
clientSecret={clientSecret}
|
|
returnUrl={returnUrl}
|
|
isHide={
|
|
selectedPaymentMethod !== EPaymentMethod.PAYMENT_BUTTONS
|
|
}
|
|
onAvailable={(_isAvailable, _availableMethods) =>
|
|
onAvailableExpressCheckout(_isAvailable, _availableMethods)
|
|
}
|
|
onChangeLoading={(isLoading) =>
|
|
setIsLoadingExpressCheckout(isLoading)
|
|
}
|
|
/>
|
|
</Elements>
|
|
<Elements stripe={stripePromise} options={{ clientSecret }}>
|
|
<CheckoutForm
|
|
confirmType={paymentType}
|
|
subscriptionReceiptId={paymentIntentId}
|
|
returnUrl={returnUrl}
|
|
isHide={selectedPaymentMethod !== EPaymentMethod.CREDIT_CARD}
|
|
/>
|
|
</Elements>
|
|
</>
|
|
)}
|
|
</div>
|
|
<SecurityPayments />
|
|
<p className={styles.address}>1123 Rimer Dr Moraga, California 94556</p>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default PaymentModal;
|