122 lines
3.1 KiB
TypeScript
122 lines
3.1 KiB
TypeScript
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<PaymentRequest | null>(
|
|
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 && (
|
|
<PaymentRequestButtonElement
|
|
className={styles["stripe-element"]}
|
|
options={{
|
|
paymentRequest,
|
|
style: { paymentRequestButton: { height: "60px" } },
|
|
}}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default ApplePayButton;
|