GithubHelp home page GithubHelp logo

Comments (11)

ribeiroguilherme avatar ribeiroguilherme commented on May 27, 2024

Hi @wecessary ,

Thanks for pointing it out, we will investigate this soon. I am assuming that you are facing this problem on all Next 14.x versions.. Did you also test on 14.0.0?

from adyen-web.

wecessary avatar wecessary commented on May 27, 2024

Hi @ribeiroguilherme thanks for taking notice. I actually just tested on Next js 13.5.6 and the same issue occurred. So I think the problem has to to with at least Next js 13.5.6 and up.

from adyen-web.

wecessary avatar wecessary commented on May 27, 2024

@ribeiroguilherme Just to add. I just tested on Nextjs v13.5.1 and same issue also occurred. So v13.4.19 happens to be the last compatible version.

Also if it is relevant. I mount the drop in component by doing the following. Simplified code:

  "use client";
   import AdyenCheckout from "@adyen/adyen-web";

function Page(){
   const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    async function initPaymentSession() {
      if (!ref.current) return;

      const res = await fetch("/api/checkout/get-payment-methods", {
        method: "POST",
        body: JSON.stringify({ cartId, locale }),
      });
      const data = await res.json();
      const checkout = await AdyenCheckout(
        getConfig({
          router,
          paymentMethodsResponse: data,
          cartId,
        })
      );

      checkout.create("dropin").mount(ref.current);
    }
    initPaymentSession();
  }, [router, cartId, locale]); 
  }


function getConfig({
  router,
  paymentMethodsResponse,
  cartId,
}: {
  router: AppRouterInstance;
  paymentMethodsResponse: any;
  cartId: string;
}) {
  return {
    paymentMethodsResponse,
    clientKey: process.env.NEXT_PUBLIC_ADYEN_CLIENT_KEY as string,
    locale: "en-US",
    environment: "test",
    analytics: {
      enabled: true,
    },
    amount:{ value:1000, currency:"GBP"},
    onSubmit: async (state: any, dropin: any) => {
      const res = await fetch("/api/checkout/make-payment", {
        method: "POST",
        body: JSON.stringify({
          cartId,
          paymentData: state.data,
        }),
      });
      const data = await res.json();
      if (data.action) {
        dropin.handleAction(data.action);
      } else {
        if (data.resultCode) {
          router.push(
            `/uk/checkout/result?resultCode=${data.resultCode}&order=${data.merchantReference}`
          );
        }
      }
    },
    onAdditionalDetails: async (state: any, dropin: any) => {
      const res = await fetch("/api/checkout/additional-details", {
        method: "POST",
        body: JSON.stringify({
          additionalDetails: state.data.details,
        }),
      });
      const data = await res.json();
      if (data.action) {
        dropin.handleAction(data.action);
      } else {
        if (data.resultCode) {
          router.push(
            `/uk/checkout/result?resultCode=${data.resultCode}&order=${data.merchantReference}`
          );
        }
      }
    },

    setStatusAutomatically: true,
    onError: (error: any, component: any) => {
      console.error("fail", error.name, error.message, error.stack, component);
    },
    threeDS2: {
      challengeWindowSize: "05",
    },
    paymentMethodsConfiguration: {
      card: {
        hasHolderName: true,
        holderNameRequired: true,
        billingAddressRequired: true,
        name: "Credit or debit card",
      },
    },
  };
}

from adyen-web.

ribeiroguilherme avatar ribeiroguilherme commented on May 27, 2024

Hi @wecessary

Thanks for sharing the code. Is it happening specifically with the 3DS action, or also with other action types? Can you let me know which other payment methods is this happening?

Did you try only Drop-in, or also with standalone Component?

from adyen-web.

wecessary avatar wecessary commented on May 27, 2024

@ribeiroguilherme When /payments response didn't have an action object, it worked fine. It also wasn't working when action.type was redirect. I only tested action types that have to do with 3ds. We are only planning on taking Visa, Mastercard and Amex so I think these are the only two action types I need to be concerned with...?

I only tried Drop-in.

Just a hunch so feel free to ignore it: According to the React doc, changing a ref doesn't trigger re-render. So refs are apparently not appropriate for storing information that need to change visually. But Adyen doc says to use ref. So I was actually surprised when I saw 3ds or even loading state work for the first time. Maybe something to do with this? But actually if this was the issue that even the older Next js versions should have the same problem I guess

from adyen-web.

ribeiroguilherme avatar ribeiroguilherme commented on May 27, 2024

Hey @wecessary ,

I created a repo trying to reproduce this problem using adyen-web with Nextjs 14.0.3, and everything seems to work as expected, including handleAction part. You can check it here

Can you take a look and let me know if I am missing something?

from adyen-web.

wecessary avatar wecessary commented on May 27, 2024

Thanks @ribeiroguilherme! I'll look at it today - will get back to you today or tomorrow (UK time)

from adyen-web.

wecessary avatar wecessary commented on May 27, 2024

Hey @ribeiroguilherme, I found the issue!

In the following code, if you get rid of the if statement, and just run loadAdyen() in the useEffect, somehow, 3ds UI will not work with NextJs 14, but will work with Next 13.4.19.

  useEffect(() => {
    if (!isAdyenWebInitialized.current) {
      isAdyenWebInitialized.current = true;
      loadAdyen();
    }
  }, [loadAdyen]);

I have made two branches for you to see:

  1. Next 14 - 3ds doesn't work. link
  2. Next 13.4 - 3ds works. link

I also updated React to 18.2.0 in both branches, just beacuse that's what I'm using.

This is super interesting! Keen to know your thinking! Also, may I ask your reason behind using isAdyenWebInitialized?

FYI, the card I have been using to test is:
5454 5454 5454 5454
03/30 737

from adyen-web.

ribeiroguilherme avatar ribeiroguilherme commented on May 27, 2024

That is the reason that I added the isAdyenWebInitialized .

I believe the issue is that React is running on strict mode , which causes the effects to re-run an extra time.

Re-running the effect can lead the library to be reinitialized twice or even multiple times depending on your implementation. This can lead to many bugs. One problem for example is a race condition situation, where you might end up rendering your checkout using one AdyenCheckout instance, but then handling actions using another AdyenCheckout instance. The code is asynchronous, so you can't know which one will finish/render first.

For the reason above, we need to add a mechanism to prevent the initialization to happen multiple times.

Can you confirm that this 'check' fixes the problem on Nextjs 13 too?

from adyen-web.

wecessary avatar wecessary commented on May 27, 2024

That makes sense. I can also confirm that this 'check' fixes the problem on Nextjs 13.4.19 too.

I think you're right on this one. Nextjs doc says

Since Next.js 13.4, Strict Mode is true by default with app router, so the above configuration is only necessary for pages. You can still disable Strict Mode by setting reactStrictMode: false.

This explains why the issue appeared only in dev mode and only on Next 14 but not on Next 13.4. I just wasn't aware...

Perhaps the use of this 'check' is worth adding to the doc? The doc currently just warns React and Vue developers to "make sure that you use references instead of selectors" (advanced flow or simple flow)

Thank you so so much for your help @ribeiroguilherme! I learnt something in the process too!

from adyen-web.

ribeiroguilherme avatar ribeiroguilherme commented on May 27, 2024

Glad that it worked @wecessary 🙏 I will forward your feedback to the docs team so they can update the documentation accordingly. Cheers!

from adyen-web.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.