#CheerfulGolem

1 messages · Page 1 of 1 (latest)

solemn spokeBOT
wide ridge
#

hi! can you share the full code you've written?

marble hemlock
#

Frontend and Backend right?

wide ridge
#

frontend to start with since it's a frontend error

marble hemlock
#

Give me one secod

#

Ehh message too long

#

PaymentForm.tsx


const SubscriptionPaymentForm: React.FC<Props> = ({ email }) => {
    const [clientSecret, setClientSecret] = useState('');
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState<string | null>(null);

    const publicURL = process.env.NEXT_PUBLIC_VERCEL_URL?.includes('http')
        ? process.env.NEXT_PUBLIC_VERCEL_URL
        : `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`;

    const returnURL = `${publicURL}/explore`;

    useEffect(() => {
        setLoading(true);
        // Create PaymentIntent as soon as the page loads
        axios
            .post(
                '/api/company/create-business-subscription',
                {
                    email,
                },
                {
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    withCredentials: true,
                }
            )
            .then((res) => {
                setClientSecret(res.data.clientSecret);
                setLoading(false);
            })
            .catch((err) => {
                setError('Something went wrong. Please try again later');
            });
    }, [email]);

    const options: StripeElementsOptions = {
        clientSecret,
        appearance: {
            theme: 'stripe',
            variables: {
                colorPrimary: '#3b82f6',
            },
        },
    };

    return (
         <>
            {!clientSecret || loading || error ? (
               <div>Loading...
</div>): (
                <Elements options={options} stripe={stripePromise}>
                    <CheckoutForm
                        email={email}
                        isLoading={loading}
                        setIsLoading={setLoading}
                        returnURL={returnURL}
                    />
                </Elements>
            )}
        </>
    );
};
#

(sending the checkoutform as well one second)

#

CheckoutForm.tsx

const CheckoutForm: React.FC<Props> = ({ returnURL, handleFormSubmit, setIsLoading }) => {
    const stripe = useStripe();
    const elements = useElements();

    const [email, setEmail] = useState('');

    useEffect(() => {
        if (!stripe) {
            return;
        }

        const clientSecret = new URLSearchParams(window.location.search).get(
            'payment_intent_client_secret'
        );

        if (!clientSecret) {
            return;
        }

        // stripe.retrievePaymentIntent(clientSecret).then(({ paymentIntent }) => {});
    }, [stripe]);

    const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
        event.preventDefault();

        if (!stripe || !elements) {
            // Stripe.js has not yet loaded.
            // Make sure to disable form submission until Stripe.js has loaded.
            return;
        }

        setIsLoading(true);

        const { error } = await stripe.confirmPayment({
            elements,
            confirmParams: {
                // Make sure to change this to your payment completion page
                return_url: returnURL,
                receipt_email: email,
            },
            redirect: 'if_required',
        });

        setIsLoading(false);

        if (error) {
            return;
        }

        handleFormSubmit && handleFormSubmit();
    };

    return (
        <form className="space-y-4" id="payment-form" onSubmit={(event) => handleSubmit(event)}>
            <LinkAuthenticationElement
                id="link-authentication-element"
                onChange={(event) => setEmail(event.value.email)}
            />
            <PaymentElement
                id="payment-element"
                options={{
                    layout: 'tabs',
                }}
            />
            <button type="submit">Submit</button>
        </form>
    );
};
#

I get the error when I press Submit

#

Full error:

caught (in promise) IntegrationError: Invalid value for stripe.confirmPayment(): elements should have a mounted Payment Element or Express Checkout Element. 
    at h (v3:1:435844)
    at g.betas (v3:1:437766)
    at y (v3:1:438136)
    at v3:1:383672
    at async handleSubmit (webpack-internal:///(app-client)/./app/components/checkout/CheckoutForm.tsx:37:28)
h
wide ridge
#

hmm

#

just for clarity, is the PaymentElement credit card form actually appearing on the page and you're filling it in?

marble hemlock
#

The credit card form appears, but I press submit without filling it in and it crashes

#

But regardless of if I fill it in or not, as soon as I press submit it hides the credit card form and shows error

#

Ah nevermind, I think I found the issue lol

#
   <>
            {!clientSecret || loading || error ? (
                <div className="flex items-center justify-center">
                    <p className="text-md animate-pulse font-semibold">
                        {loading && 'Loading...'}
                        {error && <span className="text-red-500">{error}</span>}
                    </p>
                </div>
            ) : (
                <Elements options={options} stripe={stripePromise}>
                    <CheckoutForm
                        email={email}
                        isLoading={loading}
                        setIsLoading={setLoading}
                        returnURL={returnURL}
                    />
                </Elements>
            )}
        </>

This bit was causing the issue

#

As soon as there would be an error, it would unmount the payment element

wide ridge
#

ah, because it destroys the DOM that the Element is mounted into

marble hemlock
#

Yea or if it starts to load