1

The paypal developer docs show how to implement the Paypal Button into Vue.js but I don't understand the code. At this point I'm not even sure if this is vue 2 or vue 3 or angular?? code.

1: import script in parent blade:

<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID"></script>

2: use button in script tag of component?

paypal.Buttons.driver("vue", window.Vue);

3: this is where I get lost, use this in app.js??:

@ng.core.Component({
  selector: 'my-app',
  template:
    <div id="app">
        <paypal-buttons [props]="{
            createOrder: createOrder,
            onApprove: onApprove
        }"></paypal-buttons>
    </div>
  ,
})
class AppComponent {
    createOrder(data, actions) {
      return actions.order.create({
          purchase_units: [{
              amount: {
                  value: '0.01'
              }
          }]
      });
    }
    onApprove(data, actions) {
      return actions.order.capture();
    }
}
@ng.core.NgModule({
    imports: [
        ng.platformBrowser.BrowserModule,
        paypal.Buttons.driver('angular2', ng.core)
    ],
    declarations: [
        AppComponent
    ],
    bootstrap: [
        AppComponent
    ]
})
class AppModule {}
ng.platformBrowserDynamic
    .platformBrowserDynamic()
    .bootstrapModule(AppModule);

Could it be that this isn't even vue code but angular code?

4: and put this in the vue component??:

<div id="container">
  <app></app>
</div>
<script>
  const PayPalButton = paypal.Buttons.driver("vue", window.Vue);

  Vue.component("app", {
    // The style prop for the PayPal button should be passed in as `style-object` or `styleObject` to avoid conflict with Vue's `style` reserved prop.
    template: `
      <paypal-buttons :on-approve="onApprove" :create-order="createOrder" :on-shipping-change="onShippingChange" :on-error="onError" :style-object="style" />
    `,
    components: {
      "paypal-buttons": PayPalButton,
    },

    computed: {
      createOrder: function () {
        return (data, actions) => {
          return actions.order.create({
            purchase_units: [
              {
                amount: {
                  value: "10",
                },
              },
            ],
          });
        }
      },
      onApprove: function () {
        return (data, actions) => {
          return actions.order.capture();
        }
      },
      onShippingChange: function () {
        return (data, actions) => {
          if (data.shipping_address.country_code !== 'US') {
            return actions.reject();
          }
          return actions.resolve();
        }
      },
      onError: function () {
        return (err) => {
          console.error(err);
          window.location.href = "/your-error-page-here";
        }
      },
      style: function () {
        return {
          shape: 'pill',
          color: 'gold',
          layout: 'horizontal',
          label: 'paypal',
          tagline: false
        }
      },
    },
  });

  const vm = new Vue({
    el: "#container",
  });
</script>

My question is, how would I create a simple paypal button in Vue 3's script setup? The paypal cdn is imported in the parent blade file.

Something like:

<script setup>
import {onMounted} from "vue";

onMounted(() => {
    //create component from -> paypal.Buttons.driver("vue", window.Vue);
})
</script>


<template>
  <div id="checkout" class="checkout">
    <paypal-buttons></paypal-buttons>
  </div>
</template>
2
  • 1
    The documentation is kinda messy, it shows the same angular snippet in the vue section, but below that there is the real vue snippet. Try that, or there are some posts around stackoverflow with the composition apis, like this one stackoverflow.com/questions/67249729/… Commented Jul 12, 2022 at 11:49
  • If you look closely, the first snippet after the Vue is a repetition of the one under Angular 2 using Typescript. Under this first snippet you'll find another one, using Options API (it still works in Vue3). Commented Jul 12, 2022 at 15:33

2 Answers 2

3

I would recommend the following implementation:

  • Install official paypal-js npm package: npm install @paypal/paypal-js

Then you can write your PaypalButtons Component as follows:

<script setup>
import {Inertia} from '@inertiajs/inertia';
import {loadScript} from '@paypal/paypal-js';
import {onMounted} from 'vue';

const props = defineProps({
    // Some kind of reference if you like
    reference: Object
});

onMounted(async() => {
    try {
        const paypal = await loadScript({
            'client-id': <your-paypal-client-id>
        });

        await paypal.Buttons({
            createOrder: function(data, actions) {
                return actions.order.create({
                    purchase_units: [{
                        amount: {
                            // e.g reference.price
                            value: '<your-price>',
                        },
                    }],
                });
            },
            onApprove: function(data, actions) {
                return actions.order.capture().then(function(orderData) {
                    // Successful capture!
                    // e.g. Inertia.post(route('order.update', reference.orderId)
                });
            },
            style: {
                // Adapt to your needs
                layout: 'vertical',
                color: 'gold',
                shape: 'rect',
                label: 'paypal',
            },
            // The following is optional and you can
            // limit the buttons to those you want to
            // provide
            fundingSource: paypal.FUNDING.PAYPAL,
        }).render('#paypal-button-container');
    } catch (error) {
        // Add proper error handling
        console.error(error);
    }
});
</script>

<template>
    <div id="paypal-button-container"></div>
</template>

Now use it as:

<PaypalButtons :reference="reference" />
Sign up to request clarification or add additional context in comments.

Comments

0

Paypal documentation is a huge mess. The server integration seems to work like so:

if you're using laravel as backend, import this into app.blade.php/welcome.blade.php file:

<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID"></script>

and then your vue component can look like this:

<script setup>
import {onMounted} from "vue";

onMounted(() => {
    paypal.Buttons({

        // Call your server to set up the transaction
        createOrder: function(data, actions) {
            return fetch('/demo/checkout/api/paypal/order/create/', {
                method: 'post'
            }).then(function(res) {
                return res.json();
            }).then(function(orderData) {
                return orderData.id;
            });
        },

        // Call your server to finalize the transaction
        onApprove: function(data, actions) {
            return fetch('/demo/checkout/api/paypal/order/' + data.orderID + '/capture/', {
                method: 'post'
            }).then(function(res) {
                return res.json();
            }).then(function(orderData) {
                // Three cases to handle:
                //   (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
                //   (2) Other non-recoverable errors -> Show a failure message
                //   (3) Successful transaction -> Show confirmation or thank you

                // This example reads a v2/checkout/orders capture response, propagated from the server
                // You could use a different API or structure for your 'orderData'
                var errorDetail = Array.isArray(orderData.details) && orderData.details[0];

                if (errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
                    return actions.restart(); // Recoverable state, per:
                    // https://developer.paypal.com/docs/checkout/integration-features/funding-failure/
                }

                if (errorDetail) {
                    var msg = 'Sorry, your transaction could not be processed.';
                    if (errorDetail.description) msg += '\n\n' + errorDetail.description;
                    if (orderData.debug_id) msg += ' (' + orderData.debug_id + ')';
                    return alert(msg); // Show a failure message (try to avoid alerts in production environments)
                }

                // Successful capture! For demo purposes:
                console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
                var transaction = orderData.purchase_units[0].payments.captures[0];
                alert('Transaction '+ transaction.status + ': ' + transaction.id + '\n\nSee console for all available details');

                // Replace the above to show a success message within this page, e.g.
                // const element = document.getElementById('paypal-button-container');
                // element.innerHTML = '';
                // element.innerHTML = '<h3>Thank you for your payment!</h3>';
                // Or go to another URL:  actions.redirect('thank_you.html');
            });
        }

    }).render('#paypal-button-container');
})

</script>


<template>
  <div id="checkout" class="checkout">
    <div id="paypal-button-container"></div>
  </div>
</template>

Which payment methods are displayed is determined automatically and depends on your IP (???). You can hide payment methods by manipulating the script import like so:

<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&disable-funding=card,giropay,sepa,sofort"></script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.