104 lines
2.6 KiB
TypeScript
104 lines
2.6 KiB
TypeScript
import React, { useState, useEffect, useCallback, useRef } from "react";
|
|
import { loadStripe } from "@stripe/stripe-js";
|
|
import {
|
|
EmbeddedCheckoutProvider,
|
|
EmbeddedCheckout,
|
|
Elements,
|
|
useStripe,
|
|
useElements,
|
|
} from "@stripe/react-stripe-js";
|
|
import { stripeAPI } from "../services/api";
|
|
|
|
const stripePromise = loadStripe(
|
|
process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY || ""
|
|
);
|
|
|
|
interface PaymentFormProps {
|
|
itemName: string;
|
|
total: number;
|
|
rentalData: any;
|
|
onSuccess: () => void;
|
|
onError: (error: string) => void;
|
|
disabled?: boolean;
|
|
}
|
|
|
|
const PaymentForm: React.FC<PaymentFormProps> = ({
|
|
itemName,
|
|
total,
|
|
rentalData,
|
|
onSuccess,
|
|
onError,
|
|
disabled,
|
|
}) => {
|
|
// const stripe = useStripe();
|
|
// const elements = useElements();
|
|
// const [processing, setProcessing] = useState(false);
|
|
const [clientSecret, setClientSecret] = useState<string>("");
|
|
const hasCreatedSession = useRef(false);
|
|
|
|
const createCheckoutSession = useCallback(async () => {
|
|
if (hasCreatedSession.current) return;
|
|
|
|
try {
|
|
hasCreatedSession.current = true;
|
|
const return_url = `${window.location.origin}/checkout/return?session_id={CHECKOUT_SESSION_ID}`;
|
|
|
|
const requestData = {
|
|
itemName,
|
|
total,
|
|
return_url,
|
|
rentalData,
|
|
};
|
|
|
|
const response = await stripeAPI.createCheckoutSession(requestData);
|
|
|
|
setClientSecret(response.data.clientSecret);
|
|
} catch (error: any) {
|
|
hasCreatedSession.current = false; // Reset on error so it can be retried
|
|
onError(
|
|
error.response?.data?.error || "Failed to create checkout session"
|
|
);
|
|
}
|
|
}, [itemName, total, rentalData, onError]);
|
|
|
|
useEffect(() => {
|
|
if (itemName && total > 0 && !clientSecret) {
|
|
createCheckoutSession();
|
|
}
|
|
}, [itemName, total, clientSecret, createCheckoutSession]);
|
|
|
|
return (
|
|
<div id="checkout">
|
|
{clientSecret && (
|
|
<EmbeddedCheckoutProvider
|
|
key={clientSecret}
|
|
stripe={stripePromise}
|
|
options={{ clientSecret }}
|
|
>
|
|
<EmbeddedCheckout />
|
|
</EmbeddedCheckoutProvider>
|
|
)}
|
|
{!clientSecret && (
|
|
<div className="text-center">
|
|
<div className="spinner-border" role="status">
|
|
<span className="visually-hidden">Loading payment...</span>
|
|
</div>
|
|
<p className="mt-2">Preparing payment...</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface StripePaymentFormProps extends PaymentFormProps {}
|
|
|
|
const StripePaymentForm: React.FC<StripePaymentFormProps> = (props) => {
|
|
return (
|
|
<Elements stripe={stripePromise}>
|
|
<PaymentForm {...props} />
|
|
</Elements>
|
|
);
|
|
};
|
|
|
|
export default StripePaymentForm;
|