#vm1172-reactnative
1 messages · Page 1 of 1 (latest)
Hey there
hey how you doing
so my preference is to do it inside the pay function since I do not want to create a paymentIntent every time on component mount
but when I do it inside the pay function the first time it doesn't register, and then it creates to paymentIntents
which is not ideal
sharing my pay function below
const pay = async () => {
await fetchPaymentIntentClientSecret()
if (!clientSecret) return
const { paymentIntent, error } = await confirmPlatformPayPayment(clientSecret, {
applePay: {
cartItems: cart,
merchantCountryCode: ALLOWED_COUNTRY,
currencyCode: CURRENCY.toUpperCase(),
requiredShippingAddressFields: [
PlatformPay.ContactField.Name,
PlatformPay.ContactField.PostalAddress
],
requiredBillingContactFields: [PlatformPay.ContactField.PostalAddress],
merchantCapabilities: [
ApplePayMerchantCapability.Supports3DS,
ApplePayMerchantCapability.SupportsCredit,
ApplePayMerchantCapability.SupportsDebit
]
}
})
if (error) {
console.error('Stripe Apple Pay Error', error)
} else {
console.log(JSON.stringify(paymentIntent, null, 2))
setClientSecret(null)
router.push({ pathname: '/summary', params: { paymentIntentId } })
}
}
That looks fine. Can you show me your fetchPaymentIntentClientSecret() code?
const fetchPaymentIntentClientSecret = async () => {
const token = await getItem('token')
const { paymentIntentId, clientSecret } = await CheckoutSessionAPI.createPaymentIntent(
productId,
token
)
setPaymentIntentId(paymentIntentId)
setClientSecret(clientSecret)
}
could it be that the local state isn't getting updated and i should instead return the values like so -
const fetchPaymentIntentClientSecret = async (): Promise<{
paymentIntentId: string
clientSecret: string
}> => {
const token = await getItem(')
const { paymentIntentId, clientSecret } = await CheckoutSessionAPI.createPaymentIntent(
productId,
token
)
setPaymentIntentId(paymentIntentId)
setClientSecret(clientSecret)
return { paymentIntentId, clientSecret }
}
when I try returning the paymentIntentId it does not error out the first time
but then when I try to authorize a charge it fails and returns this error
{
"code": "Failed",
"declineCode": null,
"localizedMessage": "The data couldn’t be read because it isn’t in the correct format.",
"message": "The data couldn’t be read because it isn’t in the correct format.",
"stripeErrorCode": null,
"type": null
}
Yep so what is happening is that you are using state which is asnyc
Wait actually no that should be fine.
You just click the "pay" button once here, right?
You don't have to click it twice?
Once when I changed it to returning the paymentIntentId and clientSecret from the function
twice when I was not returning it
Ah okay yeah
So that is because of the state update being async
So yes, the proper way to handle this would be to return the client secret from the function
Not set state here
Can you show me your updated code for your pay function?
const pay = async () => {
const { paymentIntentId, clientSecret } = await fetchPaymentIntentClientSecret()
if (!clientSecret) return
const { paymentIntent, error } = await confirmPlatformPayPayment(clientSecret, {
applePay: {
cartItems: cart,
merchantCountryCode: ALLOWED_COUNTRY,
currencyCode: CURRENCY.toUpperCase(),
requiredShippingAddressFields: [
PlatformPay.ContactField.Name,
PlatformPay.ContactField.PostalAddress
],
requiredBillingContactFields: [PlatformPay.ContactField.PostalAddress],
merchantCapabilities: [
ApplePayMerchantCapability.Supports3DS,
ApplePayMerchantCapability.SupportsCredit,
ApplePayMerchantCapability.SupportsDebit
]
}
})
if (error) {
if (IS_DEV_ENV) console.error('Stripe Apple Pay Error', error)
} else {
console.log(JSON.stringify(paymentIntent, null, 2))
router.push({ pathname: '/summary', params: { paymentIntentId } })
}
}
I should also mention I have a onShippingContactSelected function which calculates the tax. idk if that changes anything --
const onShippingContactSelected = async (shippingContact: ShippingContact) => {
const postalCode = shippingContact.postalAddress.postalCode
const { amount, normalizedTax } = await getTax(postalCode)
const newCart: PlatformPay.CartSummaryItem[] = [
{
label: 'Subtotal',
amount: amount.toString(),
paymentType: PlatformPay.PaymentType.Immediate
},
{
label: 'Tax',
amount: normalizedTax.toString(),
isPending: false,
paymentType: PlatformPay.PaymentType.Immediate
},
{
label: 'Shipping',
amount: '0.00',
isPending: false,
paymentType: PlatformPay.PaymentType.Immediate
},
{
label: 'Total',
amount: (amount + normalizedTax).toString(),
isPending: false,
paymentType: PlatformPay.PaymentType.Immediate
}
]
setCart(newCart)
const { error } = await updatePlatformPaySheet({
applePay: {
cartItems: newCart,
shippingMethods,
errors: []
}
})
if (error !== undefined) console.error('onShippingContactSelected', error)
const order = {
subtotal: amount,
tax: normalizedTax,
total: amount + normalizedTax
}
const token = await getItem('token')
await CheckoutSessionAPI.updatePaymentIntent(paymentIntentId, shippingContact, order, token)
}
Okay so yeah I'd recommend logging out clientSecret in your pay function
Let's see what that looks like
getTax:
const getTax = async (postalCode: string): Promise<{ amount: number; normalizedTax: number }> => {
const token = await getItem('token')
const amount = props.singlePageInfo.price
const tax = await CheckoutSessionAPI.calculateTax(amount, gentlyId, postalCode, token)
const normalizedTax = tax / 100
return { amount, normalizedTax }
}
{"clientSecret": "pi_3NxYR4Ca1hzW9vNX0d3mEAS6_secret_sVdORmexTP4xQEQMcZrDYsrdD"}
Weird... that looks fine.
Can you try hardcoding that in your confirmPlatformPayPayment() and see if you hit the same error?
sure, one second
same error, with payment failed
Stripe Apple Pay Error {"code": "Failed", "declineCode": null, "localizedMessage": "The data couldn’t be read because it isn’t in the correct format.", "message": "The data couldn’t be read because it isn’t in the correct format.", "stripeErrorCode": null, "type": null}
const { paymentIntent, error } = await confirmPlatformPayPayment(
'pi_3NxYR4Ca1hzW9vNX0d3mEAS6_secret_sVdORmexTP4xQEQMcZrDYsrdD',
{
applePay: {
cartItems: cart,
merchantCountryCode: ALLOWED_COUNTRY,
currencyCode: CURRENCY.toUpperCase(),
// shippingMethods,
requiredShippingAddressFields: [
PlatformPay.ContactField.Name,
// PlatformPay.ContactField.PhoneNumber,
PlatformPay.ContactField.PostalAddress
],
requiredBillingContactFields: [PlatformPay.ContactField.PostalAddress],
merchantCapabilities: [
ApplePayMerchantCapability.Supports3DS,
ApplePayMerchantCapability.SupportsCredit,
ApplePayMerchantCapability.SupportsDebit
]
}
}
Oh whoops, pretty sure you should be passing the parameter key here
clientSecret: 'pi_3NxYR4Ca1hzW9vNX0d3mEAS6_secret_sVdORmexTP4xQEQMcZrDYsrdD'
Try that
it’s expecting a string not an object
i’m sure i’m doing something wrong. should i share the entire file with you?
I mean it just doesn't like something you are passing to confirmPlatformPayPayment()
What countryCode are you using?
so i had this conversation prior. before it was due to an issue with shippingMethods not being a proper value inside confirmPlatformPayPayment
in this thread - #1159119746298560573 message
‘US’ only
Alright yeah it seems like that very well could be the case. I think running a quick test where you don't mess with Shipping at all would be good to confirm that
right, so i’m not messing with shipping at all. we only have one shipping method which is free shipping.
are you intimating i should remove shipping entirely from the entire payment lifecycle and try again?
Yep
I would basically just start cutting out everything not required from confirmPlatformPayPayment()
And see if we can narrow down which piece of data it doesn't like
vm1172-reactnative
got it. let me try that
shippingMethod wasn't the issue, payment still failing, will try cutting down
👋 bismarck had to head out, so I'm hopping in
Let me know iif you're having trouble pinning down which params it doesn't like
appreciate it, i need to step out for a second, is there any way to keep this thread alive?
I'll keep it up for a bit, but after a long period of inactivity we typically close threads out
If you come back after the thread is closed you can always ask again in the main channel and someone will be around to help