General information
- SDK version: 3.76.4 (also tried 3.85.2)
- Environment: Both Sandbox and Production
- Browser: Safari, Firefox
Issue description
Paypal button is not loading on Safari (this is the first browser that we observe the issue). We have implemented everything according to the documents, however it is not loading for some browsers (eg: loading for Chrome successfully). Scripts are also added under nuxt.config.js to make sure they are loading.\
\Implemented PaypalBrainTreeButton in vuejs as seen below:
<template>
<div>
<div v-show="isNewPaymentFeatureEnabled()">
<div
v-show="isButtonLoading || !isPaymentOptionsLoaded"
class="skeleton-loading-info loading t-h-11 fix-right"
/>
<div class="t-relative t-z-0">
<div
v-show="!isButtonLoading && isPaymentOptionsLoaded"
id="paypal-button"
></div>
</div>
</div>
<div v-show="!isNewPaymentFeatureEnabled()">
<div
v-show="isButtonLoading"
class="skeleton-loading-info loading t-h-11 fix-right"
/>
<div class="t-relative t-z-0">
<div v-show="!isButtonLoading" id="paypal-button"></div>
</div>
</div>
<div>
<v-overlay
:value="$store.getters.spinnerDisabled"
color="#FFFFFF"
opacity="0.7"
>
<img
src="../assets/image/modanisa-flower.png"
alt="Modanisa logo for Paypal Button"
class="t-h-20 t-w-20 rotate linear infinite t-m-auto t-block"
/>
</v-overlay>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import { mapGetters } from 'vuex'
import utils from '~/utils/utils'
declare global {
interface Paypal {
client: any
paypalCheckout: any
FUNDING: any
Buttons: any
}
interface Braintree {
paypalCheckout: any
client: any
}
interface Window {
paypal: Paypal
braintree: Braintree
}
}
@Component({
computed: {
...mapGetters({
isFeatureEnabled: 'isFeatureEnabled',
isFeatureFlagsLoaded: 'isFeatureFlagsLoaded'
})
}
})
export default class PaypalBraintreeButton extends Vue {
private currency: string =
this.$store.getters[`${this.getActiveStoreModuleName()}/currency`]
private totalPrice: string =
this.$store.getters[`${this.getActiveStoreModuleName()}/totalPrice`]
private authorizationToken =
this.$store.getters['payment/selectedPaymentOption']?.token?.braintree
private paypalClientId = utils.getPaypalClientId()
private locale = this.$store.getters.checkoutParams.language.startsWith('AR')
? 'ar_SA'
: 'en_US'
private paymentSdkScript: any = {
scripts: [
{
url: 'https://js.braintreegateway.com/web/3.76.4/js/client.min.js',
name: 'braintree-client'
},
{
url: 'https://js.braintreegateway.com/web/3.76.4/js/paypal-checkout.min.js',
name: 'braintree-paypal-checkout'
}
]
}
beforeMount(): void {
this.setupPayPal()
this.$store.dispatch('payment/buttonLoadStarted')
}
loadAllScripts(paymentSdkScript: any) {
const promises: Array<Promise<any>> = []
paymentSdkScript.scripts.forEach((script: any) => {
if (document.getElementById(script.name) !== null) {
return
}
promises.push(this.loadScript(script.url, script.name))
})
}
getActiveStoreModuleName() {
return this.$store.getters.pageParams.checkoutVersion.toLowerCase() === 'v2'
? 'checkoutV2'
: 'checkout'
}
loadScript(url: string, name: string) {
return new Promise(function (resolve, reject) {
const script = document.createElement('script')
script.src = url
script.async = false
script.setAttribute('id', name)
script.onload = function () {
resolve(url)
}
script.onerror = function () {
reject(url)
}
document.body.appendChild(script)
})
}
isNewPaymentFeatureEnabled() {
if (this.$store.getters.isFeatureFlagsLoaded) {
return this.$store.getters.isFeatureEnabled('new_payment_options')
} else {
return false
}
}
get isButtonLoading() {
return this.$store.getters['payment/spinnerEnabled']
}
get isPaymentOptionsLoaded() {
return this.$store.getters.isPaymentOptionsLoaded
}
// loadPayPalSDK(onReady: any) {
// const paypalSDK = document.createElement('script')
// paypalSDK.async = false
// paypalSDK.setAttribute(
// 'src',
// `https://www.paypal.com/sdk/js?components=buttons&client-id=${this.paypalClientId}¤cy=${this.currency}&intent=capture&locale=${this.locale}`
// )
// paypalSDK.addEventListener('load', onReady)
// document.head.appendChild(paypalSDK)
// }
setupPayPal() {
const placeOrder = (payload: any): void => {
this.$store.dispatch('spinnerDisabled', { isValid: true })
const callback = this.$store.getters.placeOrderCallback
if (callback) {
callback(this.$store.getters['payment/selectedPaymentOption'], payload)
}
}
const validate = (): boolean => {
const callback = this.$store.getters.placeOrderCallback
if (callback) {
return callback(null)
}
return false
}
const braintree = window.braintree
if (braintree === undefined || braintree.client == null) {
return this.loadAllScripts(this.paymentSdkScript)
}
const currency = this.currency
const amount = this.totalPrice
const store = this.$store
const locale = this.$store.getters.checkoutParams.language.startsWith('AR')
? 'ar_SA'
: 'en_US'
const clientID = this.paypalClientId
// Create a client.
braintree.client
.create({
authorization: this.authorizationToken
})
.then(function (clientInstance: any) {
// Create a PayPal Checkout component.
return braintree.paypalCheckout.create({
client: clientInstance
})
})
.then(function (paypalCheckoutInstance: any) {
return paypalCheckoutInstance.loadPayPalSDK({
'client-id': clientID,
currency,
intent: 'capture',
locale
})
})
.then(function (paypalCheckoutInstance: any) {
let intentId = ''
return window.paypal
.Buttons({
style: {
layout: 'horizontal',
size: 'responsive',
label: 'checkout',
tagline: 'false',
color: 'blue',
shape: 'rect'
},
fundingSource: window.paypal.FUNDING.PAYPAL,
onClick() {
return validate()
},
createOrder() {
const createPaymentIntent =
store.getters['payment/createPaymentIntent']
return createPaymentIntent().then((paymentIntentId: string) => {
intentId = paymentIntentId
return paypalCheckoutInstance.createPayment({
flow: 'checkout',
amount,
currency,
intent: 'capture'
})
})
},
onApprove(data: any) {
return paypalCheckoutInstance
.tokenizePayment(data)
.then((payload: any) => {
placeOrder({ nonce: payload.nonce, intentId })
})
},
onCancel() {
// TODO failure payment call
},
onError(err: any) {
// TODO failure payment call
// eslint-disable-next-line no-console
console.error('PayPal error', err)
}
})
.render('#paypal-button')
})
.then(function () {
store.dispatch('payment/buttonLoadCompleted')
})
}
}
</script>
<style scoped>
@media screen and (max-width: 400px) {
#paypal-button-container {
width: 100%;
}
}
@media screen and (min-width: 400px) {
#paypal-button-container {
width: 250px;
}
}
.rotate {
animation: rotation 4s;
}
.linear {
animation-timing-function: linear;
}
.infinite {
animation-iteration-count: infinite;
}
@keyframes rotation {
from {
transform: rotate(0deg);
}
to {
transform: rotate(359deg);
}
}
</style>
nuxt.config.js 's head:
head: {
title: '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{
hid: 'description',
name: 'description',
content: process.env.npm_package_description || 'checkout'
}
],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
script: [
{
src: 'https://js.braintreegateway.com/web/3.76.4/js/client.min.js'
},
{
src: 'https://js.braintreegateway.com/web/3.76.4/js/paypal-checkout.min.js'
}
]
},