#wesbos_api

1 messages ยท Page 1 of 1 (latest)

worthy reefBOT
#

๐Ÿ‘‹ 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/1250897505692946473

๐Ÿ“ Have more to share? Add details, code, screenshots, videos, etc. below.

tired ivy
#

Was chatting with @ynnoj on twitter about this. I've added to the github issue here: https://github.com/stripe/stripe-js/issues/599

ynnoj has let me know I can manually handle the actions myself via an undocumented .confirmPayment() handleActions: false, , but I rather stick with Stripe handling it all for me and just hide my modal when stripe has theirs open

GitHub

What happened? 3D Secure Authentication modals rely on a high z-index, which regardless of number is trumped by top layer elements (e.g. a dialog opened with .showModal()). This can make the modal ...

glossy heron
#

Oh hey!

tired ivy
#

hello!

glossy heron
#

Based on my understanding of the current situation, it won't be possible for Stripe.js to handle this automatically if you're using dialog

#

But I will bump this internally for more investigation.

#

Ideally we could handle this conditionally, but at minimum we should clarify the current limitation and workaround via manual actions

tired ivy
#

Okay great- I was thinking of another possible workaround. If I use the handleActions: false can I just opt to use the redirect method for 3DS that way?

glossy heron
#

I have no way to detect when the stripe modal opens
So, if you call that, you can back a requires_action PI, correct?

tired ivy
#

Okay, so:

confirmPayment() returns a paymentIntent that may have a requires_action. If it does, I can close my modal and then call handleCardAction ?

#

What about other payment methods? I essentially want to determine if I need to close my modal or not and then call .handleNextAction() . Are cards the only actions that are embedded via a modal?

glossy heron
#

Oh right, handleNextAction should account for all caes, i think, and show the 3ds modal or redirect as required

#

Definitely something you'll need to test for your flow to confirm it does what you expect for cards + other test PMs

tired ivy
#

Ok - so the next action will either be a redirect or a modal, right? So closing my modal in any case should be fine

glossy heron
glossy heron
#

(closing your modal with the Element before confirm would be a problem, since it would likely unmount the element and make the payment details inaccessible)

tired ivy
#

Oh not a problem in my case- using the browser API doesnt unmount

#

I think the only other issue I'm gonna have is the few second delay when you call handleNextAction. If I close my modal right away, then I have a few dead seconds before the nextAction happens. I'm kind of right back to wanting to find out if and when stripe shows a modal..

glossy heron
#

Hmm so you'd want to show some kind of loader UI until then? We don't currently emit any kind of event for that that I'm aware of, but might be a neat feature request.

tired ivy
#

yeah, i was snopping on window.addEventListener('message') - there is some sort of event, but im not sure which one is for stripe modal

glossy heron
#

But in the case of handleNextAction there's not necessarily an Element to tie the events too ๐Ÿค”

#

eg, if this was handleActions: true with PaymentElement, theoretically we could have paymentelement.on('actionmodal', ...)

#

But in the manual case is not clear where the .on() would go

tired ivy
#

Yeah I think it would be some sort of global API, just wanting to know when stripe opens a modal on the page

glossy heron
#

Maybe on the elements group itself? elements.on('actionmodal', ...)

tired ivy
#

even just putting a class on that div would be enough, I can watch for it

glossy heron
#

Would you be willing to share your account id (or any request id etc I can pull it from) so I can tie the feedback/feature request to that?

tired ivy
#

Yep - is that just in my stripe dashboard

#

req_kSc1tjOZ2pCkwv

glossy heron
tired ivy
#

Oh noo, So handleNextAction doesn't have an option to set redirect: "if_required", ? So there is no way to trigger the modal ?

#

and I can't set it on the confirmPayment() call either

glossy heron
#

The docs suggest if_required is the expected behaviour:

Depending on the payment method and required action, the customer may be temporarily redirected from your site and brought back to the return_url parameter provided when the PaymentIntent is confirmed.

#

What are you seeing happen?

tired ivy
#

its redirecting me to the URL isntead of putting it in a modal iframe

glossy heron
#

:/

#

Can you share the payment intent ID?

tired ivy
#

pi_2PRK474CNRdLPvsT0KpweuxG

glossy heron
#

This one does not look like you've confirmed it yet

tired ivy
#

oh yah thats because that one errored, one sec Ill do it again without redirect: "if_required",

#

pi_2PRKAt4CNRdLPvsT17GwaJpT

#

req_7e1a3cczRVHbCf is the confirmation request

glossy heron
#

Hmm interesting

#

Can you share your confirmPayment call so i can repro?

tired ivy
#
let confirmation = await stripe
      ?.confirmPayment({
        elements,
        clientSecret: intent.client_secret as string,
        confirmParams: {
          return_url: finalizeEndpoint.href,
          payment_method_data: {
            billing_details,
          },
        },
        // redirect: "if_required",
        handleActions: false, // Undocumented https://x.com/ynnoj/status/1801334076583837763
      })
glossy heron
#

Ok let me poke at this for a few minutes

tired ivy
#

Okay thanks. I'm feeling like its probably another limitation. I'm going to poke away at detecting the stripe overlay some more

worthy reefBOT
glossy heron
#

Ok, i'm still trying to work through the POC, but at a high level you'll need to modify your flow a bit to get the desired result

#

Basically, you need to separate your PE details collection from your action-handling (in order to close your modal)

#

so instead of:
1/ confirmPayment(actions:false)
2/ handle actions

you'd do:
1/ create confirmation token
2/ confirm payment with CT (confirmation token)

tired ivy
#

what is CT?

glossy heron
#
const {error, confirmationToken} = await stripe.createConfirmationToken({
      elements,
      params: {
        payment_method_data: {
          billing_details: {
            name: 'Jenny Rosen',
          }
        }
      }
    });

and

const {error} = await stripe.confirmPayment({
      clientSecret,
      confirmParams: {
        confirmation_token: '{{CONFIRMATION_TOKEN_ID}}',
        return_url: 'https://example.com/order/123/complete',
      },
    });
#

Are you familiar with the createPaymentMethod pattern?

tired ivy
#

Okay i see - and confirmPayment will pop up the modal for me?

glossy heron
#

Yes, thats right

tired ivy
#

and how do I know if its going to open the modal?

glossy heron
#

Confirmation Tokens (CT) are a bundle of the payment details and customer consent data to the presented terms

#

which can be used for later confirming a payment, without those details visible in PE any longer, either in the two-step client side pattern (think multi-step checkout or a staged funnel) or for server-side confirmation

glossy heron
tired ivy
#

hmmmm.

The thing is I dont want to close the modal because in most cases I dont need to, and I also show the success confirmation int he modal

#

I think this will work a bit better - I had looked into the paymentMethod flow instead earlier today - but it still doesnt tell me when the modal needs to open

glossy heron
#

Right, so to have that control you'd need to use the CT to confirm the PI on the server, and check whether an action is needed

#

if it goes straight to succeeded you can show your success message

tired ivy
#

ahhhh okay

glossy heron
#

If its requires_action then you use handleNextAction

#

like i said, still trying to build my POC

tired ivy
#

but handleNextAction still doesnt show a modal? Only redirects?

#

Ive gotta run to dinner - thank you for your time on this. Ill check back tomorrow.

I also have been toying with this hack to detect the modal being on the page:

function useStripeModal() {
  const [open, setOpen] = useState(false);
  // Continually check if there is a stripe modal div
  useInterval(() => {
    const stripeModal = document.querySelector(
      'div[tabindex="-1"] > iframe[name*="__privateStripeFrame"]'
    );
    setOpen(!!stripeModal);
  }, 1000);
  return open;
}
glossy heron
#

The trick here is with use_stripe_sdk -- that should be enough to get the modal for 3ds

#

just about wrapped my demo/test flow

#

Ok, yea, this works like I described ๐ŸŽ‰

#
async function createCtAndPay() {
  console.log('createCtAndPay!');
 
  const elementsSubmitResult =  await elements.submit();
  
  const createCTResult = await stripe.createConfirmationToken({
    elements,
  });
  console.log("createCTResult");
  console.log({createCTResult});
  
  const piResult = await fetch('/upe-pi-ct', {
    method: 'post',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
      confirmation_token: createCTResult.confirmationToken.id,
    })
  });
  const piData = await piResult.json();
  console.log("piResult data");
  console.log({piData});
  
  if (piData.status == "requires_action") { 
    if (piData.next_action.type=="redirect_to_url") {
      window.location.replace(piData.next_action.redirect_to_url.url);
    } else if (piData.next_action.type=="use_stripe_sdk") {
      const actionResult = await stripe.handleNextAction({
        clientSecret: piData.client_secret,
      })
      console.log("actionResult");
      console.log(actionResult);
    } else {
      console.warn('Unexpected PI next_action.type:', piData.next_action.type)
    }
  } else if (piData.status == "succeeded") {
    console.log('Payment Succeede!')
    
  } else {
      console.warn('Unexpected PI status:', piData.status)
    
  }
}
#

Server:

app.post("/upe-pi-ct", async function(request, response) {
  console.log("in /upe-pi-ct...");
  
  const { confirmation_token: confirmationTokenId } = request.body;
  
  const pi = await stripe.paymentIntents.create({
    amount: 4242,
    currency: 'usd',
    return_url: 'https://example.com/success',  
    automatic_payment_methods: {
      enabled: true,
    },
    confirm: true,
    confirmation_token: confirmationTokenId,
    use_stripe_sdk: true,
  });

  response.send({ 
    status: pi.status,
    next_action: pi.next_action,
    client_secret: pi.client_secret,
    type: 'payment'
  });
  
});
#

If you try the demo use 4000 0027 6000 3184 in the PE card form and the "Create CT & Pay PI" button

tired ivy
#

Thank you! I will review tomorrow. You are awesome - very helpful