import { useEffect, useState } from "react"; import { PaymentRequestButtonElement, useStripe, useElements, } from "@stripe/react-stripe-js"; import { PaymentRequest } from "@stripe/stripe-js"; import styles from "./styles.module.css"; import { useDispatch } from "react-redux"; import { useNavigate } from "react-router-dom"; import routes from "@/routes"; import { IPaywallProduct } from "@/api/resources/Paywall"; interface ApplePayButtonProps { activeProduct: IPaywallProduct | null; client_secret: string; subscriptionReceiptId?: string; returnUrl?: string; setCanMakePayment?: (isCanMakePayment: boolean) => void; } function ApplePayButton({ activeProduct, client_secret, subscriptionReceiptId, returnUrl, setCanMakePayment, }: ApplePayButtonProps) { const stripe = useStripe(); const elements = useElements(); const dispatch = useDispatch(); const navigate = useNavigate(); const [paymentRequest, setPaymentRequest] = useState( null ); const getAmountFromProduct = (subPlan: IPaywallProduct) => { if (subPlan.isTrial) { return subPlan.trialPrice; } return subPlan.price; }; useEffect(() => { if (!stripe || !elements || !activeProduct) { return; } const pr = stripe.paymentRequest({ country: "US", currency: "usd", total: { label: activeProduct.name || "Subscription", amount: getAmountFromProduct(activeProduct), }, requestPayerName: true, requestPayerEmail: true, }); pr.canMakePayment().then((result) => { if (result) { setPaymentRequest(pr); setCanMakePayment?.(true); } }); pr.on("paymentmethod", async (e) => { const { error: stripeError, paymentIntent } = await stripe.confirmCardPayment( client_secret, { payment_method: e.paymentMethod.id, }, { handleActions: false } ); paymentIntent; if (stripeError) { // Show error to your customer (e.g., insufficient funds) navigate( `${routes.client.paymentResult()}/${subscriptionReceiptId}/?redirect_status=failed` ); return e.complete("fail"); } navigate( returnUrl || `${routes.client.paymentResult()}/${subscriptionReceiptId}/?redirect_status=succeeded` ); e.complete("success"); // Show a success message to your customer // There's a risk of the customer closing the window before callback // execution. Set up a webhook or plugin to listen for the // payment_intent.succeeded event that handles any business critical // post-payment actions. }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [ client_secret, dispatch, elements, navigate, stripe, subscriptionReceiptId, ]); return ( <> {paymentRequest && ( )} ); } export default ApplePayButton;