#Nyxi
1 messages Β· Page 1 of 1 (latest)
π
Ahhh
Okay
So yes this can happen with Google Pay if it is a browser stored card
yeah exactly
Then 3DS will be required
I bet it was that
I have just removed this entire block and now handle it all in one instead
I didn't write this originally so I never noticed it had two different handlings for this
Do you have that original PaymentIntent example?
Yea
Hold on
pi_3M7I3iIFDslEWhBA1FfQzdN2
In hindsight, I should have searched the project for this.status = 'paid', which would have solved it
Well just glad it got figured out
Yeah me too. Sometimes rubber-ducking is really helpful
Ah actually it wasn't google/apple pay, but Link
Alright, but still it's the payment request thing
We don't actually present Google Pay for saved browser card
You do have to have it stored
So yeah
Payment Request Button still
yeah it all went through the apple pay logic
Yep exactly
so now it presumably all works
Yeah i wanted to find the actual PaymentMethod that wasn't tokenized via card element from that initial example to confirm this was the issue. And yeah, here it is: https://dashboard.stripe.com/logs/req_nMeqYWRMrSGn96
what a day
That request uses the token that Link generated
So yeah it all matches what you stated
It is just a normal card so yeah
ah yeah alright
Okay so
If SCA is required. Do I call event.complete('success'); before or after handleCardAction?
Some comments here suggest I should do it before
like because the UI is blocked otherwise
Yep you would do before
alright, moving that block then
Basically this: } else { // Report to the browser that the confirmation was successful, prompting // it to close the browser payment method collection interface. ev.complete('success'); // Check if the PaymentIntent requires any actions and if so let Stripe.js // handle the flow. If using an API version older than "2019-02-11" // instead check for: `paymentIntent.status === "requires_source_action"`. if (paymentIntent.status === "requires_action") { // Let Stripe.js handle the rest of the payment flow. const {error} = await stripe.confirmCardPayment(clientSecret); if (error) {
But instead of confirmPayment you use handleCardAction
Yeah I think that looks right. Before you make this change though, did you test out reproducing with Link?
Yeah that's fine you can use it easily in test mode
I'll give it a whirl
how? It asks for email
I add a real card to it like Apple pay etc?
You should be able to just use a test card iirc
ok i'll try
You can create test mode accounts for Link using any valid email address. The following table shows the fixed one-time passcode values that Stripe accepts for authenticating test mode accounts:
It just spins and does nothing
Also it opens in a whole new window, so how would it work for mobile?
Hmmm don't remember what the Link flow looks like on mobile
But it just spins? that's odd.
Do you have that ngrok still?
yeah it's not really behaving
It seems to be throwing some exceptions that I catch and handle incorrectly
it just spins when I input test data and then complains about multiple calls to complete
Will try. Page doesn't seem to be loading though, do you need to approve traffic or anything?
no it's just weirdly slow
it took like 30 seconds on my phone
no idea why
I even pay for ngrok
okay so it says
IntegrationError: Invalid value for status for PaymentRequest completion: value should be one of the following strings: success, fail, invalid_payer_name, invalid_payer_email, invalid_payer_phone, invalid_shipping_address. You specified: complete.
so maybe I'm just being stupid
I was sure it was complete. That's what works on Apple Pay?
It is e.complete("success")
Yeah all good
yeah so it works now
now I just need to figure out how to not call call complete twice
cause error without 3ds ends in the block, but so does error after 3ds, which already has success called
does it have a "completed" property?
Not sure I understand why you would need twice?
I don't. It complains I'm calling it twice
If there is a server error after 3ds, I will already have called complete to trigger 3ds
but I need it there because with no 3ds, i need to call it with failure
server error being any decline/insufficient funds
need like a "didcallcomplete" local variable maybe
Okay so you get the PaymentMethod then you pass to your backend to confirm again, then you either handleCardAction for 3DS or you complete because the payment was successful (or fail if unsucccessful) right?
yea
So the complete comes after you already know the backend response, right? So still not understanding the two completes
Like you use e.complete("fail") if there is an error
Yeah, but that's in a catch block, so JS runs that block if I get an error post 3DS
at which point I already called e.complete('success') to trigger 3DS
I can just use a local variable, it's just ugly
Isn't 3DS here taking place completely outside of this PRB flow? Like the PRB modal has already closed once you are handling 3DS. So it makes sense you just use e.complete("success") then prompt the 3DS modal via handleCardAction. Are you worried that is confusing to have it close the PRB modal with a success indicator and then have 3DS occur?
Feel like I'm just missing something here π
It's because it's all in one function
It's recursive, so any error in the second step bubbles up to the catch block
it's just poorly put together
I fixed it with a local variable. It works now.
Ah okay I think I see what you are saying
so it looks like this and accepts both regular payment method and payment request
handleSubmitAction(paymentMethod, applePayEvent) {
let didCompletePaymentRequest = false;
NyxService.submitConfirmation(this.$route.params.bookingID, {
email: this.formData.email,
paymentMethod,
lastEdit: this.booking.lastEdit,
})
.then((response) => {
if (response.scaResponse) {
if (applePayEvent && !didCompletePaymentRequest) {
applePayEvent.complete('success');
didCompletePaymentRequest = true;
}
this.$refs.nyxStripeComponent.handleCardAction(
response.scaResponse.clientSecret,
{ stripeAccount: response.scaResponse.stripeAccount },
)
.then(() => {
this.handleSubmitAction(null, null);
})
.catch((err) => {
this.loading = false;
this.status = 'pending';
this.onCardError(err);
if (applePayEvent && !didCompletePaymentRequest) {
applePayEvent.complete('fail');
didCompletePaymentRequest = true;
}
});
} else if (response.receiptEmail) {
this.loading = false;
this.booking.receiptEmail = response.receiptEmail;
this.status = 'paid';
if (applePayEvent && !didCompletePaymentRequest) {
applePayEvent.complete('success');
didCompletePaymentRequest = true;
}
}
})
.catch((err) => {
this.loading = false;
this.handleError(err);
if (applePayEvent && !didCompletePaymentRequest) {
applePayEvent.complete('fail');
didCompletePaymentRequest = true;
}
});
},
and yeah I should remove the else if (response.receiptEmail) { as it's the only option
It's a big mess this
everything is supposed to be moved to Vue 3 soon anyway
I think it's just the second call to it I can remove actually
yeah i'm being stupid here
this here works fine
handleSubmitAction(paymentMethod, applePayEvent) {
NyxService.submitConfirmation(this.$route.params.bookingID, {
email: this.formData.email,
paymentMethod,
lastEdit: this.booking.lastEdit,
})
.then((response) => {
if (response.scaResponse) {
if (applePayEvent) {
applePayEvent.complete('success');
}
this.$refs.nyxStripeComponent.handleCardAction(
response.scaResponse.clientSecret,
{ stripeAccount: response.scaResponse.stripeAccount },
)
.then(() => {
this.handleSubmitAction(null, null);
})
.catch((err) => {
this.loading = false;
this.status = 'pending';
this.onCardError(err);
});
} else {
this.loading = false;
this.booking.receiptEmail = response.receiptEmail;
this.status = 'paid';
if (applePayEvent) {
applePayEvent.complete('success');
}
}
})
.catch((err) => {
this.loading = false;
this.handleError(err);
if (applePayEvent) {
applePayEvent.complete('fail');
}
});
},
just tested that with Link also
Yep that looks good to me
so now to see what happens on mobile
cause normally those popups don't work with single-page-applications
My phone only shows Apple Pay though. Rip.
It doesn't even render Link if I put the browser into mobile mode
then it renders Google Pay instead
how confusing
What browser are you using?
just chrome
Do you have a card saved in Google Pay wallet at pay.google.com?
okay it totally worked on mobile
even with opening a new window
so I wonder what happens if you do that inside instagram
normally, webview browsers only allow one open page
I will try that
instagram blocks my ngrok domain for some reason, but it works in slack in-app browser. That will have to do for now.
scratch that, it doesn't. SCA modal doesn't open.
Huh so Link that requires 3DS on mobile in a in-app browser doesn't work
Makes sense actually due to the webview as you mentioned. Wonder if this has been flagged yet
If not, I'll flag it
Yeah it can't really figure out how to manage the state I think
it just returns me to the page but in the "loading" state without triggering the 3ds modal from Stripe
Gotcha
Normally, and we had a bunch of issues with this, it would have to be a query parameter redirect instead of a new window