paypal configs

Co-authored-by: Pete Matsyburka <pete@docuseal.com>
This commit is contained in:
Alex Turchyn
2026-07-28 19:27:25 +03:00
committed by Pete Matsyburka
parent 972f38242e
commit b8c29324b8
11 changed files with 334 additions and 72 deletions
+24 -2
View File
@@ -779,7 +779,10 @@ export default {
withVerification: this.withVerification,
withKba: this.withKba,
withPayment: this.withPayment,
isPaymentConnected: this.isPaymentConnected,
isStripeConnected: this.isStripeConnected,
withStripe: this.withStripe,
withPaypal: this.withPaypal,
isPaypalConnected: this.isPaypalConnected,
withFormula: this.withFormula,
withConditions: this.withConditions,
withCustomFields: this.withCustomFields,
@@ -1049,7 +1052,22 @@ export default {
required: false,
default: false
},
isPaymentConnected: {
isStripeConnected: {
type: Boolean,
required: false,
default: false
},
withStripe: {
type: Boolean,
required: false,
default: true
},
withPaypal: {
type: Boolean,
required: false,
default: false
},
isPaypalConnected: {
type: Boolean,
required: false,
default: false
@@ -1363,6 +1381,10 @@ export default {
if (document.location.search?.includes('stripe_connect_success')) {
document.querySelector('form[action="/auth/stripe_connect"]')?.closest('.dropdown')?.querySelector('label')?.focus()
}
if (document.location.search?.includes('paypal_connect_success')) {
document.querySelector('a[href^="/auth/paypal_connect"]')?.closest('.dropdown')?.querySelector('label')?.focus()
}
})
this.template.schema.forEach((item) => {
@@ -494,6 +494,7 @@ import FieldType from './field_type.vue'
import FieldSettings from './field_settings.vue'
import ContextSubmenu from './field_context_submenu.vue'
import ContextModal from './field_context_modal.vue'
import { stripeConnectedRef } from './payment_settings'
export default {
name: 'FieldContextMenu',
@@ -716,12 +717,18 @@ export default {
currentCurrency () {
return this.field.preferences?.currency || 'USD'
},
isStripeConnected: () => stripeConnectedRef.value,
priceTypeOptions () {
return [
const options = [
{ value: 'one_off', label: this.t('fixed') },
{ value: 'formula', label: this.t('formula') },
{ value: 'payment_link', label: this.t('payment_link') }
{ value: 'formula', label: this.t('formula') }
]
if (this.isStripeConnected) {
options.push({ value: 'payment_link', label: this.t('payment_link') })
}
return options
},
currentPriceType () {
if (this.field.preferences?.formula) {
@@ -1,7 +1,7 @@
<template>
<span
class="dropdown dropdown-end field-settings-dropdown"
:class="{ 'dropdown-open': withForceOpen && ((!field.preferences?.price && !field.preferences?.formula && !field.preferences?.price_id && !field.preferences?.payment_link_id) || !isConnected) && !isLoading }"
:class="{ 'dropdown-open': withForceOpen && !field.preferences?.price && !field.preferences?.formula && !field.preferences?.price_id && !field.preferences?.payment_link_id && !isLoading }"
>
<label
tabindex="0"
@@ -21,7 +21,7 @@
@click="closeDropdown"
>
<div
v-if="!('price_id' in field.preferences) && !('payment_link_id' in field.preferences)"
v-if="isPaypal || (!('price_id' in field.preferences) && !('payment_link_id' in field.preferences))"
class="field-settings-currency py-1.5 px-1 relative"
@click.stop
>
@@ -52,14 +52,14 @@
@click.stop
>
<input
v-if="'payment_link_id' in field.preferences"
v-if="isStripe && 'payment_link_id' in field.preferences"
v-model="field.preferences.payment_link_id"
placeholder="plink_XXXXX"
class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0"
@blur="save"
>
<input
v-else-if="'price_id' in field.preferences"
v-else-if="isStripe && 'price_id' in field.preferences"
v-model="field.preferences.price_id"
placeholder="Price ID: price_XXXXX"
class="input input-bordered input-xs w-full max-w-xs h-7 !outline-0"
@@ -89,7 +89,10 @@
>
{{ 'payment_link_id' in field.preferences ? t('payment_link') : t('price') }}
</label>
<div class="flex items-center justify-center">
<div
v-if="isStripe && stripeConnected"
class="flex items-center justify-center"
>
<a
href="#"
class="hover:underline"
@@ -120,21 +123,22 @@
</div>
</div>
<div
v-if="!isConnected || isOauthSuccess"
class="field-settings-stripe-connect py-1.5 px-1 relative"
v-if="!stripeConnected && !paypalConnected"
class="flex flex-col gap-1 py-1.5 px-1"
@click.stop
>
<div
v-if="isConnected && isOauthSuccess"
class="text-sm text-center"
<a
v-if="withPaypal"
:href="paypalConnectUrl"
target="_blank"
data-turbo="false"
class="btn bg-[#003087] hover:bg-[#012169] btn-sm text-white w-full"
>
<IconCircleCheck
class="inline text-green-600 w-4 h-4"
/>
Stripe Connected
</div>
<IconBrandPaypal class="w-4 h-4 inline" />
<span>Connect PayPal</span>
</a>
<form
v-if="!isConnected"
v-if="withStripe"
data-turbo="false"
action="/auth/stripe_connect"
accept-charset="UTF-8"
@@ -170,33 +174,25 @@
:disabled="isLoading"
class="btn bg-[#7B73FF] hover:bg-[#0A2540] btn-sm text-white w-full"
>
<span
<IconInnerShadowTop
v-if="isLoading"
class="flex items-center space-x-1"
>
<IconInnerShadowTop
class="w-4 h-4 animate-spin inline"
/>
<span>
Connect Stripe
</span>
</span>
<span
class="w-4 h-4 animate-spin inline"
/>
<IconBrandStripe
v-else
class="flex items-center space-x-1"
>
<IconBrandStripe
class="w-4 h-4 inline"
/>
<span>
Connect Stripe
</span>
</span>
class="w-4 h-4 inline"
/>
<span>Connect Stripe</span>
</button>
</form>
</div>
<div
v-if="isStripe && !stripeConnected"
class="px-1 pb-1.5"
@click.stop
>
<a
v-if="!isConnected"
class="block link text-center mt-1"
class="block link text-center text-xs"
href="https://www.docuseal.com/blog/accept-payments-and-request-signatures-with-ease"
target="_blank"
data-turbo="false"
@@ -272,24 +268,25 @@
</template>
<script>
import { IconMathFunction, IconSettings, IconCircleCheck, IconInfoCircle, IconBrandStripe, IconInnerShadowTop, IconRouteAltLeft, IconForms } from '@tabler/icons-vue'
import { IconMathFunction, IconSettings, IconInfoCircle, IconBrandStripe, IconBrandPaypal, IconInnerShadowTop, IconRouteAltLeft, IconForms } from '@tabler/icons-vue'
import { ref } from 'vue'
const isConnected = ref(false)
export const stripeConnectedRef = ref(false)
export const paypalConnectedRef = ref(false)
export default {
name: 'PaymentSettings',
components: {
IconSettings,
IconCircleCheck,
IconRouteAltLeft,
IconInfoCircle,
IconForms,
IconMathFunction,
IconInnerShadowTop,
IconBrandStripe
IconBrandStripe,
IconBrandPaypal
},
inject: ['backgroundColor', 'save', 'currencies', 't', 'isPaymentConnected'],
inject: ['backgroundColor', 'save', 'currencies', 't', 'isStripeConnected', 'isPaypalConnected', 'withStripe', 'withPaypal'],
props: {
field: {
type: Object,
@@ -318,13 +315,27 @@ export default {
}
},
computed: {
isConnected: () => isConnected.value,
isOauthSuccess () {
return document.location.search?.includes('stripe_connect_success')
stripeConnected: () => stripeConnectedRef.value,
paypalConnected: () => paypalConnectedRef.value,
provider () {
if (this.paypalConnected && !this.stripeConnected) return 'paypal'
if (this.stripeConnected && !this.paypalConnected) return 'stripe'
if (this.withPaypal && !this.withStripe) return 'paypal'
return 'stripe'
},
isStripe () {
return this.provider === 'stripe'
},
isPaypal () {
return this.provider === 'paypal'
},
redirectUri () {
return document.location.origin + '/auth/stripe_connect/callback'
},
paypalConnectUrl () {
return `/auth/paypal_connect?redir=${encodeURIComponent(document.location.href)}`
},
defaultCurrencies () {
return ['USD', 'EUR', 'GBP', 'CAD', 'AUD']
},
@@ -363,26 +374,53 @@ export default {
mounted () {
this.field.preferences.currency ||= this.defaultCurrency
isConnected.value ||= this.isPaymentConnected
stripeConnectedRef.value ||= this.isStripeConnected
paypalConnectedRef.value ||= this.isPaypalConnected
if (!this.isConnected) {
this.checkStatus()
if (this.withStripe && !this.stripeConnected && !this.paypalConnected) {
this.checkStripeStatus()
}
if (this.withPaypal && !this.paypalConnected && !this.stripeConnected) {
this.checkPaypalStatus()
window.addEventListener('focus', this.onWindowFocus)
}
},
beforeUnmount () {
window.removeEventListener('focus', this.onWindowFocus)
},
methods: {
checkStatus () {
onWindowFocus () {
if (this.withPaypal && !this.paypalConnected) {
this.checkPaypalStatus()
}
},
checkStripeStatus () {
this.isLoading = true
fetch('/api/stripe_connect').then(async (resp) => {
const { status } = await resp.json()
if (status === 'connected') {
isConnected.value = true
stripeConnectedRef.value = true
window.removeEventListener('focus', this.onWindowFocus)
}
}).finally(() => {
this.isLoading = false
})
},
checkPaypalStatus () {
fetch('/api/paypal_connect').then(async (resp) => {
const { status } = await resp.json()
if (status === 'connected') {
paypalConnectedRef.value = true
window.removeEventListener('focus', this.onWindowFocus)
}
})
},
closeDropdown () {
document.activeElement.blur()
}