import clsx from 'clsx'; import {Button} from '@common/ui/buttons/button'; import {FormEventHandler, Fragment, ReactNode, useState} from 'react'; import {useStripe} from '@common/billing/checkout/stripe/use-stripe'; import {Skeleton} from '@common/ui/skeleton/skeleton'; interface StripeElementsFormProps { productId?: string | number; priceId?: string | number; type: 'setupIntent' | 'subscription'; submitLabel: ReactNode; returnUrl: string; } export function StripeElementsForm({ productId, priceId, type = 'subscription', submitLabel, returnUrl, }: StripeElementsFormProps) { const {stripe, elements, paymentElementRef, stripeIsEnabled} = useStripe({ type, productId, priceId, }); const [errorMessage, setErrorMessage] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); // disable upgrade button if stripe is enabled, but not loaded yet const stripeIsReady: boolean = !stripeIsEnabled || (elements != null && stripe != null); const handleSubmit: FormEventHandler = async e => { e.preventDefault(); // stripe has not loaded yet if (!stripe || !elements) return; setIsSubmitting(true); try { const method = type === 'subscription' ? 'confirmPayment' : 'confirmSetup'; const result = await stripe[method]({ elements, confirmParams: { return_url: returnUrl, }, }); // don't show validation error as it will be shown already by stripe payment element if (result.error?.type !== 'validation_error' && result.error?.message) { setErrorMessage(result.error.message); } } catch {} setIsSubmitting(false); }; return (
{stripeIsEnabled && }
{errorMessage && !isSubmitting && (
{errorMessage}
)}
); } function StripeSkeleton() { return ( ); }