PaddleHQ / paddle-js-wrapper

Wrapper to load Paddle.js as a module and use TypeScript definitions when working with methods.
Apache License 2.0
41 stars 6 forks source link

[Bug]: Unable to Dynamically Set Event Callbacks for Paddle Instance #27

Closed FarhanAtAppyHigh closed 7 months ago

FarhanAtAppyHigh commented 7 months ago

What happened?

Hi, We have encountered an issue with our web application's payment flows. We currently support two payment methods: subscription and pay-as-you-go. Previously, we initialized Paddle at runtime when the user clicked on either flow. This approach allowed us to optimize performance by loading/intialize Paddle dynamically only when necessary, thereby avoiding initial page load overhead.

However, a new requirement has emerged to add pwCustomer: object during Paddle initialization for Retain (ProfitWell Engagement) analytics purposes. To meet this requirement, we need to initialize Paddle in our NextJS layout so that it is declared on each page, as per the recommendation in your documentation. Unfortunately, this change has introduced a complication.

Since we now have only one Paddle instance declared, we are unable to set up different event callbacks based on the selected payment flow (such as redirections are different for both inline payment checkout). Initially, I attempted to dynamically add event callbacks based on the payment flow using:

const { paddleInstance, setPaddleInstance } = usePaddle();
useEffect(() => {
    initializePaddle({
        environment: paddleEnvironment,
        token: paddleClientToken,
        eventCallback: function (data: any) {
            console.log('came: ',data);
        },
        pwCustomer: {},
    }).then((paddleInstance: Paddle | undefined) => {
        if (paddleInstance) {
            setPaddleInstance(paddleInstance);
        }
    });
}, []);

const handleSubs = () => setPaddleInstance((prev)=> return {...prev, eventCallback: forSubscriptionCallbback() });
const handlePayAsYouGo = () => setPaddleInstance((prev)=> return {...prev, eventCallback: forPayAsYouGoCallbback() });

handleSubs, handlePayAsYouGo are the functions they get called and I tried to change eventCallback for particular case before calling paddleInstance.checkout()

but encountered an issue: only the event callbacks initialized first are working properly. so how can i change these based on different inline checkout flows?

Also, for adding Retain (ProfitWell Engagement) support in our codebase, suggestions from Richard (from the Paddle team) were that further along in the user journey, when we have userEmail, we have to set pwCustomer with userEmail in our paddleInstance. I think this will also not work, as we are not able to dynamically set/change paddleInstance.

Steps to reproduce

  1. create paddleintance in react/next app try setting initially eventCallback, pwCustomer: blank/basic initialized values
  2. before checkout try changing eventCallback for different/multiple payment flows.
  3. also when user sign in and its email is generated, try adding pwCustomer dynamically to paddleInstance, for retain analytics ...

What did you expect to happen?

  1. There should be a procedure on how to change/manipulate the paddleInstance based on certain requirements in between user-journey.

How are you integrating?

  1. NextJS with npm paddle-js-wrapper library
vijayasingam-paddle commented 7 months ago

Hi @FarhanAtAppyHigh ,

Thank you for raising a detailed report.

This bug is very close to #20 and we are working on a strategic solution that will make it easy to use Paddle JS with SPA.

I will let you know once we have a fix for this problem.

vijayasingam-paddle commented 7 months ago

Hi @FarhanAtAppyHigh, We released a fix to handle this issue.

If you are using initializePaddle it should now accept multiple calls and take updated values for pwCustomer or eventCallback

or if you are calling paddle.Setup manually you can replace that with the below snippet. paddle.Initialize is the new name for paddle.Setup, functionally they do the same thing. paddle.Update will accept the same shape of data as Initialize but reset the properties with new value.

if (paddle.Initialized) {
  paddle.Update({ ...props });
} else {
  paddle.Initialize({ ...props });
}

Note: We have't updated our documentation with the new functions yet. It should be updated in a few days

Thank you.

vijayasingam-paddle commented 7 months ago

Hello, I am going to close this issue as it is fixed. Please feel free to create a new issue if you face any other problems.

Thank you.

FarhanAtAppyHigh commented 7 months ago

Hello @vijayasingam-paddle ,

I appreciate your efforts in addressing this issue promptly and providing the necessary fixes. I'm pleased to report that we have successfully integrated the retain flow. I conducted tests today, and everything appears to be functioning properly!

Once again, thank you for your swift response and effective resolution.