#FKaiB
1 messages ยท Page 1 of 1 (latest)
Where is your PaymentElement created? I don't see it in your code
// Fetch the clientSecret from your server here and set the state
// For example:
fetch("http://localhost:4242/create-payment-intent", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ items: [{ id: "your-item-id" }] }),
})
.then((res) => res.json())
.then((data) => {
setClientSecret(data.clientSecret);
});
}, []);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!stripe || !elements || !clientSecret) {
// 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: "http://localhost:3000",
},
});
if (error.type === "card_error" || error.type === "validation_error") {
setMessage(error.message as string);
} else {
setMessage("An unexpected error occurred.");
}
setIsLoading(false);
};
const paymentElementOptions = {
layout: "tabs",
};
return (
<form id="payment-form" onSubmit={handleSubmit}>
<LinkAuthenticationElement
id="link-authentication-element"
onChange={(e) => setEmail(e.value.email)}
/>
<PaymentElement
id="payment-element"
options={paymentElementOptions as StripePaymentElementOptions}
/>
<button disabled={isLoading || !stripe || !elements} id="submit">
<span id="button-text">
{isLoading ? <div className="spinner" id="spinner"></div> : "Pay now"}
</span>
</button>
{/* Show any error or success messages */}
{message && <div id="payment-message">{message}</div>}
</form>
);
}```
I use it in the component CheckoutForm. Above is part of the code.
How does your <Elements> link with <CheckoutForm>? <CheckoutForm> should be wrapped within <Elements>, but I don't see it in your code
I'd recommend checking how CheckoutForm should be set within Elements here: https://stripe.com/docs/payments/quickstart
In addition, you shouldn't need to create Payment Intent again in CheckoutForm
It should be something like:
<div className="App">
{clientSecret && (
<Elements options={options} stripe={stripePromise}>
<CheckoutForm />
</Elements>
)}
</div>
I have the CheckoutForm as a grand child of the Chatspert component. Chatspert -> BillingPopUp -> CheckoutForm.
and the <Chatspert > component is wrapped in <Elements>
does <ChecoutForm> have to directly be wrapped by <Elements>?
I also used the exmple from the quickstart guide
Not necessary, but it depends on how your React components are implemented
If you try to put <CheckoutForm> directly under <Elements>, does it work?
I tried
<Elements options={options} stripe={stripePromise}>
<CheckoutForm />
</Elements>```
Inside the <BillingPopUp> file but I still get the same error.
How is your <BillingPopUp> set? How is it related to <Elements> and <CheckoutForm>? I don't have full visibility of how your components, so can't tell where goes wrong
let me go back several steps. So I was following the quickstart guide and had "options" defined as below just how it was done in the example code.
const appearance = {
theme: "stripe",
};
const options = {
clientSecret,
appearance,
};```
However in typescript I was getting this error
Type '{ clientSecret: string; appearance: { theme: string; }; }' is not assignable to type 'StripeElementsOptions | undefined'.
Type '{ clientSecret: string; appearance: { theme: string; }; }' is not assignable to type 'StripeElementsOptionsMode'.
Types of property 'clientSecret' are incompatible.
Type 'string' is not assignable to type 'undefined'.
This is why I got rid of the "apperance" variiable which seems to get rid of the error. But now in the console, I am getting the error shared earlier in the thread. I believe for some reason, the "clientSecret" variable is not read correctly in <Elements>. I confirmed that the clientSecret does display the correct clientSecret when console logging.
And to answer your question, <BillingPopUp> is a simple modal that pops up when a user clicks on a button. And this is how the CheckoutForm is used as of now.
Which version of @stripe/react-stripe-js are you using?
From your options parameter and <Elements>, the setting look correct
^2.1.0
Can you share the reproducible code that I can run? From the partial codes you shared, I don't have full visibility how your app works
I will make one right now
๐
You have to replace the "CHANGE_ME" in App.tsx and sever.py to your API key
thanks for doing this btw. I am really stuck and I needed help
In the code you shared, I don't see <Elements> being used in App.tsx, BillingPopUp.tsx, Chatpert.tsx or CheckoutForm.tsx
This is what I received:
oop sorry. it should be
<Elements options={options} stripe={stripePromise}>
<Chatspert />
</Elements>
}
in <Route>
When I hardcoded clientSecret to an actual client secret, it works:
(with import { StripeElementsOptions } from '@stripe/stripe-js';)
const options: StripeElementsOptions = {
clientSecret: "pi_3MwcAJF3hM0gtZIC0C07NY5Z_secret_jAoZ3j7863i6kmoJ1PcBTlVM6",
appearance: {
theme: 'stripe'
},
};
It seems like the elements is rendered before client secret is created
After I modify your code to:
{clientSecret && <Route path="/" element={
<Elements options={options} stripe={stripePromise}>
<Chatspert />
</Elements>
} />}
It will work
Elements will only show after clientSecret is set
Just add clientSecret check and your code will work fine