import { useState, type FormEvent } from 'react' import { PaymentElement, useStripe, useElements } from '@stripe/react-stripe-js' import type { StripePaymentElementOptions } from '@stripe/stripe-js' export interface StripePaymentFormProps { amount: number currency?: string onSuccess: (paymentIntentId: string) => void onError: (error: string) => void isProcessing?: boolean submitLabel?: string } export function StripePaymentForm({ amount, currency = 'EUR', onSuccess, onError, isProcessing = false, submitLabel, }: StripePaymentFormProps) { const stripe = useStripe() const elements = useElements() const [isSubmitting, setIsSubmitting] = useState(false) const [errorMessage, setErrorMessage] = useState(null) const [isReady, setIsReady] = useState(false) const loading = isProcessing || isSubmitting const label = submitLabel || `Pay ${currency.toUpperCase()} ${amount.toFixed(2)}` const paymentElementOptions: StripePaymentElementOptions = { layout: 'tabs', } async function handleSubmit(e: FormEvent) { e.preventDefault() if (!stripe || !elements) return setIsSubmitting(true) setErrorMessage(null) const { error, paymentIntent } = await stripe.confirmPayment({ elements, redirect: 'if_required', }) if (error) { // PaymentIntent already succeeded (webhook race) — treat as success if (error.payment_intent && error.payment_intent.status === 'succeeded') { onSuccess(error.payment_intent.id) setIsSubmitting(false) return } setErrorMessage(error.message || 'Payment failed') onError(error.message || 'Payment failed') setIsSubmitting(false) return } if (paymentIntent && paymentIntent.status === 'succeeded') { onSuccess(paymentIntent.id) } else if (paymentIntent) { setErrorMessage('Payment requires additional action') onError('Payment requires additional action') } setIsSubmitting(false) } return (
setIsReady(true)} /> {errorMessage && (
{errorMessage}
)} ) }