#reikoBooop
1 messages · Page 1 of 1 (latest)
Hi there, can you share with me the relevant code?
Hi there its the base code that I have, I think its caused by calling discount endpoint (which created by us). When we call discount api, it will return new totalAmount and cartObject.totalAmount is the one in below code.
const [options, setOptions] = useState<StripeElementsOptions | undefined>(undefined);
const [stripeCardPromise, setStripeCardPromise] = useState<Stripe | null>(null);
useEffect(() => {
const getData = async () => {
if (process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY && cartObject) {
const stripeObject = await loadStripe(process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY); // getting stripe object for Stripe credit card element payment
setOptions({
mode: 'payment',
// discounted amount should reflect to card payment
amount: cartObject.totalAmount,
currency: 'aud',
payment_method_types: ['card'],
paymentMethodCreation: 'manual',
appearance: {
theme: 'stripe',
variables: {
colorPrimary: '#0570de',
colorBackground: '#ffffff',
colorText: '#30313d',
colorDanger: '#df1b41',
fontSizeBase: '12px',
borderRadius: '5px',
spacingUnit: '4.25px'
},
rules: {
'.Label': {
textTransform: 'uppercase',
fontSize: '1rem',
marginBottom: '0.25rem',
color: '#4a5568'
}
}
}
});
if (stripeObject) {
setStripeCardPromise(stripeObject);
}
}
};
if (process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY && cartObject) getData();
}, [cartObject?.totalAmount]);
// Discount
const [discountPending, setDiscountPending] = useState(false);
const [discountTotal, setDiscountTotal] = useState(0);
const handleDiscount = async () => {
setDiscountPending(true);
const { data: cartWithDiscount, error: cartWithDiscountError } = await getDiscount({
cartId: cartObject?._id,
discountCode: removeWhiteSpace(forms.discount)
});
if (cartWithDiscount) {
setCartObject({ ...cartWithDiscount, paymentIntentClientSecret: cartObject?.paymentIntentClientSecret });
setDiscountPending(false);
setShowDiscountModal(false);
}
if (cartWithDiscountError) {
setValidation({ ...validation, discount: "The code you entered doesn't exist. Please check and try again." });
setDiscountPending(false);
console.log(cartWithDiscountError);
}
};
{/* manual card */}
{Object.keys(selectedPayment).length > 0 && stripeCardPromise !== null && options !== null ? null : (
<div className="w-full md:w-1/2 px-3">
<Elements stripe={stripeCardPromise} options={options}>
<CreditCardForm
setErrorMessage={setErrorMessage}
setPageIsLoading={setPageIsLoading}
checkoutData={checkoutData}
forms={forms}
handleChange={handleChange}
cartObject={cartObject}
setTransaction={setTransaction}
validation={validation}
setValidation={setValidation}
/>
</Elements>
</div>
)}
It looks like loadStripe is called again when cartObject?.totalAmount changes. I don't think it's necessary to do this
You may just call stripe.fetchUpdate when the PaymentIntent amount changes. see https://stripe.com/docs/js/elements_object/fetch_updates
Sorry I had look the doc but how do I use this?? If you can let me know where I can use this
I assume you'll update the amount of the PaymentIntent when the cartObject?.totalAmount changes? am I righjt?
Yes that correct
OK, I guess you send a request from frontend to you backend to update the PaymentIntent, once your frontend receives the response from your backend, you can call stripe.fetchUpdateso that Elements can fetch the update from the assocaited PaymentIntent.
Ive added const { error: fetchUpdatesError } = await elements.fetchUpdates();
if (fetchUpdatesError) {
console.log('fetchUpdatesError', fetchUpdatesError);
return;
}
just before const { error, paymentMethod } = await stripe.createPaymentMethod({
elements,
params: {
billing_details: {
email: forms.email
}
}
});
But then I get below error, what am i doing wrong?
Uncaught (in promise) IntegrationError: In order to call fetchUpdates, you must pass a valid PaymentIntent or SetupIntent client secret when creating the Elements group.
e.g. stripe.elements({clientSecret: "{{CLIENT_SECRET}}"})
at t.<anonymous> (v3:1:291013)
at t.fetchUpdates (v3:1:64873)
at handleCreditCard (CreditCardForm.tsx:84:1)
Did you pass a valid client_secret to stripe.elements() ?
Sorry I never passed client_secret to stripe.elements, quite frankly I dont even know how I can pass client_secret to elements
https://stripe.com/docs/payments/accept-a-payment?platform=web&ui=elements&client=react#add-and-configure-the-elements-provider-to-your-payment-page are you following this integration guide?
Similar but I believe it was different doc I was following...
I tried to pass the clientSecret but somehow I get type error Type 'string' is not assignable to type 'undefined'.ts(2322) but its not undefined i am passing client secret starting with pi_ and has secret in the middle
useEffect(() => {
const getData = async () => {
if (cartObject && cartObject?.paymentIntentClientSecret) {
setOptions({
mode: 'payment',
clientSecret: cartObject.paymentIntentClientSecret,
// discounted amount should reflect to card payment
amount: cartObject.totalAmount,
currency: 'aud',
payment_method_types: ['card'],
paymentMethodCreation: 'manual',
appearance: {
theme: 'stripe',
variables: {
colorPrimary: '#0570de',
colorBackground: '#ffffff',
colorText: '#30313d',
colorDanger: '#df1b41',
fontSizeBase: '12px',
borderRadius: '5px',
spacingUnit: '4.25px'
},
rules: {
'.Label': {
textTransform: 'uppercase',
fontSize: '1rem',
marginBottom: '0.25rem',
color: '#4a5568'
}
}
}
});
}
};
if (cartObject?.paymentIntentClientSecret) getData();
}, [cartObject]);
Sorry I was passing wrong client secret, once sec
I'd also suggest you do a conditional rendering that only renders Elements if client_seret is available
The documentation you sent across is bit different from what I followed...the documation that I used I could get paymentMethod id from stripe.cretatePaymentMethod() then I can pass the paymentMethod.id to get paymentIntent.
What document are you following? send me the link
OK. It's still the same, you need to create a PaymentIntent upfront in order to render the PaymentElement
It's worth mentioning that there's another flow that you might want to consider: https://stripe.com/docs/payments/accept-a-payment-deferred it allows you to render the PaymentElement without creating a Intent
but with the document I sent through, I only get integration error if I have different totalAmount so I can technically use the initial doc right?
I just confused why changing totalAmount cause the integration error to start with?
Did you see the PaymentElement rendered successfully before changing the amount?
yes it does render perfectly, in fact there is no error if I dont change the amount and payment goes through fine
When you change the amount, do you also change anything related to Stripe?
only the option property as I am passing amount to Elements from the options
setOptions({
mode: 'payment',
// discounted amount should reflect to card payment
amount: cartObject.totalAmount,
currency: 'aud',
payment_method_types: ['card'],
paymentMethodCreation: 'manual',
appearance: {
theme: 'stripe',
variables: {
colorPrimary: '#0570de',
colorBackground: '#ffffff',
colorText: '#30313d',
colorDanger: '#df1b41',
fontSizeBase: '12px',
borderRadius: '5px',
spacingUnit: '4.25px'
},
rules: {
'.Label': {
textTransform: 'uppercase',
fontSize: '1rem',
marginBottom: '0.25rem',
color: '#4a5568'
}
}
}
});
}
};
Hmm, wait. It looks you are using the deferred flow already https://stripe.com/docs/payments/accept-a-payment-deferred
I believe you are doing something similar to this https://stripe.com/docs/payments/accept-a-payment-deferred?platform=web&type=payment#dynamic-updates
Yes it is, the weird thing is that I get integration error only when I have change totalAmount and type in phone number (which is stored in completely separate state)
so not necessary changing the totalAmount is causing this integration error
following is the summary of when I encounter the error. I initially thought that phone number is triggering this error but seems more like combination of both. On top of that, we actually did not have this error previously, we just encounter this error from this week
with phone number + different totalAmount -> error
without phone number + different totalAmount -> success
with phone number + same totalAmount -> success
without phone number + same totalAmount -> success
Are you using AddressElement to collect the phone number?
no im using separate input field to collect phone number
OK, so you build your own input field to collect phone? hmm, how can your input field affect stripe elements?
not entirely sure how.... im also using separate input field for email address but that doesn't seem to have any affect on stripe elements
Can you remove the phone field temporarily and see if it works?
Yes if I remove phone field it does work with same amount & different amount
I initially thought Stripe element have same field of phone so I change name to phoneNumber but didnt change anything
<input
className={shadow-input appearance-none border ${ validation.phoneNumber ? 'border-warning' : null } rounded-md w-full py-3 px-2 text-xs text-gray-700 leading-tight focus:outline-none focus:shadow-outline}
type="text"
placeholder="04123 456 789"
name="phoneNumber" // used to be phone
value={forms.phoneNumber}
onChange={handleChange}
onBlur={checkPhone}
/>
how do you put this input and stripe elements together?
like below, its not even in the same component.. PaymentElement tag is inside of CreditCardForm
<input
className={shadow-input appearance-none border ${ validation.phoneNumber ? 'border-warning' : null } rounded-md w-full py-3 px-2 text-xs text-gray-700 leading-tight focus:outline-none focus:shadow-outline}
type="text"
placeholder="04123 456 789"
name="phoneNumber"
value={forms.phoneNumber}
onChange={handleChange}
onBlur={checkPhone}
/>
{/* manual card */}
{Object.keys(selectedPayment).length > 0 && stripeCardPromise !== null && options !== null ? null : (
<div className="w-full md:w-1/2 px-3">
<Elements stripe={stripeCardPromise} options={options}>
<CreditCardForm
setErrorMessage={setErrorMessage}
setPageIsLoading={setPageIsLoading}
checkoutData={checkoutData}
forms={forms}
handleChange={handleChange}
cartObject={cartObject}
setTransaction={setTransaction}
validation={validation}
setValidation={setValidation}
/>
</Elements>
</div>
)}
Hmm, that's really strange
I know its quite odd one
does stripe offer input field for phone number?