javascriptreactjsamazon-pay

Access Script Tag Callback from React - AmazonPay


I am in the process of integrating AmazonPay into a React SPA. The classic integration relies on script tags and callbacks (docs).

Here is one example from the button widget:

<head>
  <script type='text/javascript'>
    window.onAmazonLoginReady = function() {
      amazon.Login.setClientId('CLIENT-ID');
    };
    window.onAmazonPaymentsReady = function() {
                showButton();
    };
  </script>
    <script async="async" src='https://static-na.payments-amazon.com/OffAmazonPayments/us/sandbox/js/Widgets.js'>
  </script>
</head>

<body>
. . .
 <div id="AmazonPayButton">
 </div>
  ...
 <script type="text/javascript">
    function showButton(){
      var authRequest; 
      OffAmazonPayments.Button("AmazonPayButton", "SELLER-ID", { 
        type:  "TYPE", 
        color: "COLOR", 
        size:  "SIZE", 

        authorization: function() { 
        loginOptions = {scope: "SCOPES", 
          popup: "POPUP-PARAMETER"}; 
        authRequest = amazon.Login.authorize (loginOptions, 
          "REDIRECT-URL"); 
        }, 

        onError: function(error) { 
          // your error handling code.
          // alert("The following error occurred: " 
          //        + error.getErrorCode() 
          //        + ' - ' + error.getErrorMessage());
        } 
     });
    }; 
   </script>
   . . .
   <script type="text/javascript">
     document.getElementById('Logout').onclick = function() {
       amazon.Login.logout();
     };
   </script>

</body>

When using React, the div with id="AmazonPayButton" isn't on the page until React mounts the div, causing the window.showButton() function to fail.

To circumvent this issue, I've wrapped the function showButton() definition inside window.showButton():

    window.onAmazonPaymentsReady = function() {

        window.showButton = function () {

            var authRequest;

            // eslint-disable-next-line no-undef
            OffAmazonPayments.Button("AmazonPayButton", "%REACT_APP_AMAZON_SELLER_ID_SANDBOX%", {
                type: "PwA",
                color: "Gold",
                size: "medium",
                authorization: function () {
                    loginOptions = {
                        scope: "profile postal_code payments:widget payments:shipping_address",
                        popup: true
                    };
                    authRequest = amazon.Login.authorize(loginOptions, "%PUBLIC_URL%/pay-with-amazon");
                },
                onError: function (error) {
                    console.log(error.toString())
                }
            });
        };
    };

The component which contains the AmazonPay div can now be called on componentDidMount:

import React, {Component} from 'react'

class AmazonMethod extends Component {

    componentDidMount () {
        window.showButton()
    }

    render() { return <div id="AmazonPayButton"></div>}
}

export default AmazonMethod

I am confused how to access the onError callback from inside my React component. How do I listen for the callback and respond appropriately?

This question applies to AddressWidget and WalletWidget as well; they all rely on script tag callbacks.

Update: I've written a post which summarizes how to integrate AmazonPay with client side React.


Solution

  • Why don't you just pass in a function to your showButton function in componentDidMount that onError can call?

    Something like this:

    window.onAmazonPaymentsReady = function() {
    
        window.showButton = function (errorFunc) {
    
            var authRequest;
    
            // eslint-disable-next-line no-undef
            OffAmazonPayments.Button("AmazonPayButton", "%REACT_APP_AMAZON_SELLER_ID_SANDBOX%", {
                type: "PwA",
                color: "Gold",
                size: "medium",
                authorization: function () {
                    loginOptions = {
                        scope: "profile postal_code payments:widget payments:shipping_address",
                        popup: true
                    };
                    authRequest = amazon.Login.authorize(loginOptions, "%PUBLIC_URL%/pay-with-amazon");
                },
                onError: function (error) {
                    console.log(error.toString())
                    errorFunc(error)
                }
            });
        };
    };
    
    
    import React, {Component} from 'react'
    
    class AmazonMethod extends Component {
    
    componentDidMount () {
        window.showButton(this.errorFunc)
    }
    
    errorFunc = (error) => {
        console.log(error);
    
       this.setState({
            amazonError: error
       });
    }
    
    render() { return <div id="AmazonPayButton"></div>}
    }
    
    export default AmazonMethod