#Daniel-paymentintent
1 messages · Page 1 of 1 (latest)
Hi!
So you get the intent data on the redirect url after submitting your purchase.
That's correct
Is there any way to handle those smoothlie with react-router(-dom)?
What do you mean by that?
Hey!
I´m currently trying to build my "pending page", so the page constantly checking for the payment status update
import { useState, useEffect } from 'react';
import { useStripe } from '@stripe/react-stripe-js';
import { PaymentIntentResult } from '@stripe/stripe-js';
const PaymentStatus = () => {
const stripe = useStripe();
const [message, setMessage] = useState<String>('');
useEffect(() => {
if (!stripe) {
return;
}
// Retrieve the "payment_intent_client_secret" query parameter appended to
// your return_url by Stripe.js
const clientSecret = new URLSearchParams(window.location.search).get(
'payment_intent_client_secret'
);
// Retrieve the PaymentIntent
stripe
.retrievePaymentIntent(clientSecret!)
.then(({ paymentIntent }: PaymentIntentResult) => {
// Inspect the PaymentIntent `status` to indicate the status of the payment
// to your customer.
//
// Some payment methods will [immediately succeed or fail][0] upon
// confirmation, while others will first enter a `processing` state.
//
// [0]: https://stripe.com/docs/payments/payment-methods#payment-notification
switch (paymentIntent!.status) {
case 'succeeded':
setMessage('Success! Payment received.');
break;
case 'processing':
setMessage(
"Payment processing. We'll update you when payment is received."
);
break;
case 'requires_payment_method':
// Redirect your user back to your payment page to attempt collecting
// payment again
setMessage('Payment failed. Please try another payment method.');
break;
default:
setMessage('Something went wrong.');
break;
}
});
}, [stripe]);
return <p>message</p>
};
export default PaymentStatus;
thats the payment status component by the official docs
problem is, I don´t know how i can render it
because now if i try to import it and render it in my index.tsx checkout page, which atm just looks like this:
import PaymentStatus from './PaymentStatus';
const CheckingPayment = () => {
return (
<div>
CheckingPayment
<PaymentStatus />
</div>
);
};
export default CheckingPayment;
I get an error telling me that i can only use the useStripe hook when the component is wrapped in an elements component
wait, let me check smth
okay nvm, I´m kinda lost right here. It tells me like I said I need to useStripe in an Elements provider.
But the elementsprovider is in a way different react component
so i need to make a second one?
hello 👋
taking over here
what's your component hierarchy?
I think it works, I just did it like so
looks like this in a nutshell, one sec...
<Routes>
<Route "/createOrder" element=... /> <-- In Here is the first Elements provider by Stripe with the loadStripe(key) -> <Elements stripe={stripePromise}></Elements>
<Route "/pendingPage" element=... /> <-- In Here is the second Elements provider by Stripe, loading the same Promise via loadStripe with the same key again
</Routes>
does it make sense?
ah
so you're trying to render <Elements /> twice?
Is it possible to just nest the component that handles routing in <Elements />?
hmmm two questions:
can this have any performance issues?
what if I have a second product to sell
would that work with one promise?
if its all fine i can wrap it around my routes ig
but yeah, thats exactly my issue rn
it works, but I don´t know if its smart
Let me take a look
sure thanks!
So we usually recommend using the provider at the root
https://stripe.com/docs/stripe-js/react#elements-provider
You could definitely use this for more than single product.
if its all fine i can wrap it around my routes ig
yup that's would be ideal
awesome, thanks alot! Appreciate your quick help on the discord ❤️
NP! 🙂 Good luck
I actually do have another question. So if I want to put it in the root level, I´d have to create the clientSecret on the initial page load, would that be right?
Yup that's correct
Ight
v3:1 Uncaught (in promise) IntegrationError: Invalid value for elements(): clientSecret should be a client secret of the form ${id}_secret_${secret}. You specified: .
any idea what this error is about?
import { FC, useEffect, useState } from 'react';
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import { createPayment } from '../backendRequests/PaymentRequests/createPayment';
const stripePromise = loadStripe(
'pk_test_51KyzygLkVu8CqnKeoQeb1C6bHnn0axEfI040HfOqdwIirE3CSfbRS385TflBhDug5A2sQminFBDdmqnH5E9By3i200ky6OKWdD'
);
interface StripeAppearance {
theme: 'stripe' | 'night' | 'flat' | 'none' | undefined;
}
const StripeProvider: FC = ({ children }) => {
const [clientSecret, setClientSecret] = useState<string>('');
useEffect(() => {
// Create PaymentIntent as soon as the page loads
createPayment(setClientSecret);
}, []);
const appearance: StripeAppearance = {
theme: 'stripe'
};
const options = {
clientSecret,
appearance
};
return (
<Elements options={options} stripe={stripePromise}>
{children}
</Elements>
);
};
export default StripeProvider;
this is my component pretty much on the root level of my app rn
wrapping my Routes component
can you try printing clientSecret before you pass it into options?
you mean before i render the elements object?
yup
I can try
dunno if the promise comes back that fast
refreshing the page ends in those errors
well actually the same lol
fixed it
return (
<>
{clientSecret ? (
<Elements options={options} stripe={stripePromise}>
{children}
</Elements>
) : (
children
)}
</>
);
needed to wait for the clientSecret to be set before rendering <Elements>
you may want to change this
<Elements options={options} stripe={stripePromise}>
{children}
</Elements>
) : (
children
)}```
to
clientSecret && ( .... )
the code that you had is similar to if....else
oooh
so it still renders children without elements if no clientSecret
thought it would rerender tho on setstate with the elements provider than
but seems not to 😄
yeah you would get the error on initial render and the code would stop running after that point