#hayen_error
1 messages ยท Page 1 of 1 (latest)
Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.
- hayen_unexpected, 6 days ago, 11 messages
๐ Welcome to your new thread!
โฒ๏ธ We'll be here soon! We typically respond in a few minutes, but in some cases we might need a bit more time (e.g., server's busy, you've got a complex question, etc.).
โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can start a new thread if you have another question.
๐ This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1257434915041968221
๐ Have more to share? Add details, code, screenshots, videos, etc. below.
child component where the client secret is created, in the onSubmit function of the form:
// Create payment intent
let paymentIntent = await createPaymentIntentApi(cart.key, metadata, vatRate, vatData).catch(
(error) => {
setMessage(error.message);
setIsLoading(false);
return;
}
);
console.log("Created stripe payment intent: ", paymentIntent);
const { clientSecret: clientSecret } = paymentIntent // response.data
// Pass the client secret to the parent. clientSecret state will then be updated in parent (checkout.js)
if (clientSecret) {
console.log(clientSecret);
onClientSecretGenerated(clientSecret); // Pass the client secret to the parent
} else {
throw new Error('Client secret not found');
}
checkout.js (the parent):
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);
export default function Checkout() {
const {cart} = useContext(CartContext);
const [clientSecret, setClientSecret] = useState('');
const appearance = {
theme: 'stripe',
};
const options = {
appearance,
mode: 'payment',
amount: grandTotal,
currency: 'eur',
// paymentMethodTypes: ['card', 'ideal', 'paypal'],
paymentMethodTypes: ['card', 'ideal', 'paypal'],
};
if (clientSecret) {
options.clientSecret = clientSecret;
}
return (
<Layout>
{ searchParams.get('redirect_status') === 'failed' && (
<div className={styles.error}>
<p>There was an error processing your payment. Please try again.</p>
</div>
) }
<Container>
<Elements options={options} stripe={stripePromise}>
<CheckoutContainer onClientSecretGenerated={setClientSecret} />
</Elements>
</Container>
</Layout>
)
}
Hello, taking a step back, can you tell me more about what you are trying to do here? Are you trying to initialize your Elements page without a payment intent and then update the price or something later?
Oh yeah I forgot to say, later in the code of the child component (where the client secret is created) I am using fetchUpdates()
fetchUpdates is intended for our flow where you start by creating a PaymentIntent before you initialize Elements. Basically the intent defines the price, available payment methods and such, so if those change on the intent you need to call fetchUpdates but if you are working without an intent, the Elements instance defines those things so you can just update the elements instance
and when I am not using fetchUpdates, everything works fine and it doesn't give me any errors about the clientsecret
But I need to use the fetchUpdates function because I have bug whenever the user is trying to pay with Google Pay , the price isn't correct for some reason (atleast that is what your collague told me)
But the fetchUpdates function requires a clientsecret that is being passed to the Elements component
So that's why I am trying to do it like this
I am not really following you. So it is not correct to use fetchUpdates in my case?
Correct, you should be updating the price through this method https://docs.stripe.com/js/elements_object/update
fetchUpdates is only for the flow where you initialize Elements with a client secret
I am using this function because your collague told me that it would solve the problem when the price is not correct. Let's say I am from the Netherlands and the VAT is 21% and my product is 1.00, but when using Google Pay, and selecting the Netherlands it shows 1.00 instead of 1.21. But when selecting IDEAL it shows 1.21, which is correct. So it only happens when using Google Pay
And your collague gave as a solution, to use fetchUpdates
That's why I am a bit confused
My colleague may have thought that you were using that other flow
fetchUpdates is only for the flow that you are not currently using. Updating the elements object is the way to indicate the pricing change with your current setup
Okay I understand
But I am bit confused because whenever selecting GooglePay in the PaymentElement, it shows 1.00 at first in the google payment screen. And after a succesfull checkout, when I look in my stripe dashboard it does show 1.21, which is correct
Basically the Apple and Google Pay sheet don't have a concept of the Stripe payment. Elements has to tell them what price to display, so if Elements has an outdated idea of what the price is, so will the google or apple pay sheet
But how come IDEAL and paypal etc. show the price correctly immediately?
It just happens with Google Pay
Immediately when what happens? before you call fetchUpdates or update the elements object?
No I haven't even used fetchUpdates, and I am definitely not going to use it anymore because you told me it doesn't work with my flow right?
Oh, are iDEAL and PayPal on an entirely different page? It may be that our server properly coordinates things before the redirect if that is the case
And right, but I am trying to understand where you are updating the price that updates it for iDEAL and PayPal. I was not aware that that could happen but am happy to look in to what is happening when I have more details of what your integration is doing here
No it's not on a different page
Wait I can show you a screenshot
Or wait eh
Not it is on a different page sorry
When selecting ideal it sends me to a different page
Same goes for paypal
It's just google pay because google doesn't redirect to a different page
Gotcha, that makes sense. So by that point there is a PaymentIntent with the amount that you actually want to charge, so at that point my guess is that we reference the actual price when talking to PayPal or iDEAL. We could probably also retrieve the price on the frontend as well, but at the moment we expect you to update the price as it changes
Oh, so for Google Pay price to show the correct price I MUST update the price using the elements.update function
Hmm it is still not updating in google pay screen
Can you check my code?:
export default function Checkout() {
const {cart} = useContext(CartContext);
const [grandTotal, setGrandTotal] = useState(0);
const [grandTotalFetched, setGrandTotalFetched] = useState(false); // New state variable
const searchParams = useSearchParams();
const elementsRef = useRef(null); // Ref to store the Elements instance
useEffect(() => {
if (cart && cart.items) {
// Calculate grand total
const newGrandTotal = cart.items.reduce(
(total, item) => total + item.quantity * item.price,
0
);
setGrandTotal(newGrandTotal);
}
}, [cart]);
useEffect(() => {
if (elementsRef.current) {
elementsRef.current.update({
amount: grandTotal
});
}
}, [grandTotal]);
if(!grandTotal) {
return (
<Layout>
<Container>
<div className={styles.successPage}>
<h1>Your cart is empty!</h1>
<center>Return to the <Link href="/">homepage</Link></center>
</div>
</Container>
</Layout>
)
}
const appearance = {
theme: 'stripe',
};
const options = {
// clientSecret,
appearance,
mode: 'payment',
amount: grandTotal,
currency: 'eur',
// paymentMethodTypes: ['card', 'ideal', 'paypal'],
paymentMethodTypes: ['card', 'ideal', 'paypal'],
};
return (
<Layout>
<Elements options={options} stripe={stripePromise} onReady={(elements) => {
elementsRef.current = elements; // Store the Elements instance
}}>
<CheckoutContainer />
</Elements>
</Container>
</Layout>
)
}
๐
Stepping in for my teammate. I'm not a React expert so may need to pull in another teammate. Are you able to log grandTotal?
Yes, before I answer your question i think i'd have to ask this first to be sure i am not using element.update in the wrong place
should elements.update be placed in the same file as where the options are passed to the Elements component?
because useElements is used in another file
Let's take step back for a second. Could you summarize for me where you're blocked? Also, to be clear, are you using both the PaymentElement and the ExpressCheckoutElement or just the PaymentElement?
I am just using PaymentElement
I think I am just confused on where to use elements.update
Before I didn't use elements.update and the total amount was correctly shown when selecting IDEAL or Paypal, but not in the Google Pay screen
When using IDEAL or Paypal it redirect you to a different page
when selecting Google Pay you just stay on the same page
Sorry, I'm having a bit of trouble understanding where you're blocked.
So you're creating a PaymentIntent and using its client secret to render the PaymentElement. Is that correct? If so, are customers doing something client side (e.g., updating their cart) to require an update to the PaymentIntent's amount?
So apparently I have to use https://docs.stripe.com/js/elements_object/update. Google Pay is not updating the amount on screen, when you select google pay it shows the price without VAT
Only after the payment is done it will show up correctly with VAT included in the stripe dashboard
So in order
I am initializing the PaymentElement by doing this:
const options = {
// clientSecret,
appearance,
mode: 'payment',
amount: grandTotal,
currency: 'eur',
// paymentMethodTypes: ['card', 'ideal', 'paypal'],
paymentMethodTypes: ['card', 'ideal', 'paypal'],
};
return (
<Layout>
{ searchParams.get('redirect_status') === 'failed' && (
<div className={styles.error}>
<p>There was an error processing your payment. Please try again.</p>
</div>
) }
<Container>
<Elements options={options} stripe={stripePromise} onReady={(elements) => {
elementsRef.current = elements; // Store the Elements instance
}}>
<CheckoutContainer />
</Elements>
</Container>
</Layout>
)
As you can see Elements component is placed in the Container and the options are passed to the Elements component
In the CheckoutContainer. component I am creating the payment intent and the clientSecret are created in the handleSubmit function:
const metadata = {
selectedPaymentMethod,
firstName: formValues.firstName,
lastName: formValues.lastName,
email: formValues.email,
address: formValues.address,
address2: formValues.address2,
postalCode: formValues.postalCode,
city: formValues.city,
country: countryCodes[formValues.countryCode].name,
countryCode: formValues.countryCode,
priceTotal: totalAmount,
priceTotalVAT: totalVAT,
vatNumber: formValues.vatNumber,
vatValid: vatData ? vatData.Valid : false,
vatName: vatData ? vatData.Name : null,
vatAddress: vatData ? vatData.Address + vatData.CountryCode : null,
vatCountryCode: vatData ? vatData.CountryCode : null,
newsletterSignup: typeof formValues.newsletterSignup.checked !== 'boolean' ? true : formValues.newsletterSignup.checked,
};
// Create payment intent
let paymentIntent = await createPaymentIntentApi(cart.key, metadata, vatRate, vatData).catch(
(error) => {
setMessage(error.message);
setIsLoading(false);
return;
}
);
console.log("Created stripe payment intent: ", paymentIntent);
const { clientSecret: clientSecret } = paymentIntent // response.data
and after that the payment is confirmed:
//Confirm the payment
const { error } = await stripe.confirmPayment({
elements,
clientSecret,
confirmParams: {
return_url: returnURL,
payment_method_data: {
billing_details: {
address: {
city: formValues.city,
country: formValues.countryCode,
line1: formValues.address,
line2: formValues.address2, // Optional?
postal_code: formValues.postalCode,
// state: TODO! add state in inputs
},
name: formValues.firstName,
email: formValues.email,
// phone: formValues.phone // Optional
}
},
},
});
Here you have a screenshot of what I am expecting to see in Google Pay, IDEAL, Paypal etc
So price that has to be shown is 1.21 including 21% vat, because I've selected the Netherlands. Price without vat is 1.00
But for some reason, when selecting Google Pay on production it is showing me this:
And when I click on 'pay' and stripe.confirmPayment is executed, when I check my stripe dashboard it succesfully charged me 1.21
So your collague advised me to use elements.update() to solve this problem
I am stuck because I am stuck on using elements.update()
I've tried doing something like elements.update(amount: ...) and passed an amount, but it is not showing any changes. Amount is still 1.00 on the Google pay screen
Just to make sure I follow. In the GooglePay screenshot above, the price shows 1.00 but you're saying that if you complete the payment from that screen, you see a 1.21 charge?
Yes that is correct, but it only happens when using Google Pay. It shows the price correctly when selecting IDEAL or Paypal, because those two redirect you to a different page
Hi there ๐ taking over, as my colleague needs to step away
Give me a few minutes to get caught up.
Yes, no problem
Can you paste the relevant code with the element.update() line?
You can't pass an amount into elements.update(): https://docs.stripe.com/js/elements_object/update_payment_element
Oh whut your colleague send me this: https://docs.stripe.com/js/elements_object/update
this documentation looks different
But do I even need to use element.update or elements.update for my problem?
Another colleague advised me to use elements.fetchUpdates(), but that also didn't work
Starting from here I am explaining things in chronologically order
It's getting pretty late here, can you please leave this open? I have put so much effort into explaining evrything to you guys and it hasn't been solved yet. Don't want to explain everything all over again tomorrow