feat: Adds paypal as a fiat choice (#3637)

Co-authored-by: Vlad Stan <stan.v.vlad@gmail.com>
This commit is contained in:
Arc
2025-12-09 14:35:39 +02:00
committed by GitHub
co-authored by Vlad Stan
parent 661b713993
commit baee90da67
13 changed files with 1034 additions and 33 deletions
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+9 -2
View File
@@ -74,6 +74,8 @@ window.localisation.en = {
update_name: 'Update name',
fiat_tracking: 'Fiat tracking',
fiat_providers: 'Fiat providers',
fiat_warning_bitcoin:
'Fiat providers can get twitchy about anything bitcoin, so avoid using word "bitcoin" in your memos!',
currency: 'Currency',
update_currency: 'Update currency',
press_to_claim: 'Press to claim bitcoin',
@@ -237,6 +239,7 @@ window.localisation.en = {
webhook_url: 'Webhook URL',
webhook_url_hint:
'Webhook URL to send the payment details to. It will be called when the payment is completed.',
copy_webhook_url: 'Copy webhook URL',
webhook_events_list: 'The following events must be supported by the webhook:',
webhook_stripe_description:
'One the stripe side you must configure a webhook with a URL that points to your LNbits server.',
@@ -428,8 +431,7 @@ window.localisation.en = {
look_and_feel: 'Look and Feel',
endpoint: 'Endpoint',
api: 'API',
api_stripe:
'API (warning: Stripe are twitchy about anything bitcoin, so avoid using word "bitcoin" in your memos!)',
api_stripe: 'API',
api_token: 'API Token',
api_tokens: 'API Tokens',
access_control_list: 'Access Control List',
@@ -706,10 +708,15 @@ window.localisation.en = {
filter_labels: 'Filter labels',
filter_date: 'Filter by date',
websocket_example: 'Websocket example',
client_id: 'Client ID',
secret_key: 'Secret Key',
signing_secret: 'Signing Secret',
signing_secret_hint:
'Signing secret for the webhook. Messages will be signed with this secret.',
webhook_id: 'Webhook ID',
webhook_id_hint: 'PayPal webhook ID used to verify incoming events.',
webhook_paypal_description:
'On the PayPal side configure a webhook pointing to your LNbits server.',
callback_success_url: 'Callback Success URL',
callback_success_url_hint:
'The user will be redirected to this URL after the payment is successful',
+5
View File
@@ -628,10 +628,15 @@ window.localisation.fi = {
filter_payments: 'Suodata maksuja',
filter_date: 'Suodata päiväyksellä',
websocket_example: 'Websocket example',
client_id: 'Client ID',
secret_key: 'Secret Key',
signing_secret: 'Signing Secret',
signing_secret_hint:
'Signing secret for the webhook. Messages will be signed with this secret.',
webhook_id: 'Webhook ID',
webhook_id_hint: 'PayPal webhook ID used to verify incoming events.',
webhook_paypal_description:
'On the PayPal side configure a webhook pointing to your LNbits server.',
callback_success_url: 'Callback Success URL',
callback_success_url_hint:
'The user will be redirected to this URL after the payment is successful'
@@ -5,10 +5,79 @@ window.app.component('lnbits-admin-fiat-providers', {
data() {
return {
formAddStripeUser: '',
formAddPaypalUser: '',
hideInputToggle: true
}
},
computed: {
stripeWebhookUrl() {
return (
this.formData?.stripe_payment_webhook_url ||
this.calculateWebhookUrl('stripe')
)
},
paypalWebhookUrl() {
return (
this.formData?.paypal_payment_webhook_url ||
this.calculateWebhookUrl('paypal')
)
}
},
watch: {
formData: {
handler() {
this.syncWebhookUrls()
},
immediate: true
}
},
methods: {
basePathFromLocation() {
if (typeof window === 'undefined') {
return ''
}
const normalizedPath = window.location.pathname.replace(/\/+$/, '')
const adminIndex = normalizedPath.lastIndexOf('/admin')
const basePath =
adminIndex >= 0
? normalizedPath.slice(0, adminIndex)
: normalizedPath || ''
return basePath || ''
},
calculateWebhookUrl(provider) {
if (typeof window === 'undefined') {
return ''
}
const basePath = this.basePathFromLocation()
const path = `${basePath}/api/v1/callback/${provider}`.replace(
/\/+/g,
'/'
)
const withLeadingSlash = path.startsWith('/') ? path : `/${path}`
return `${window.location.origin}${withLeadingSlash}`
},
syncWebhookUrls() {
this.maybeSetWebhookUrl('stripe_payment_webhook_url', 'stripe')
this.maybeSetWebhookUrl('paypal_payment_webhook_url', 'paypal')
},
maybeSetWebhookUrl(fieldName, provider) {
if (!this.formData) {
return
}
const calculated = this.calculateWebhookUrl(provider)
const current = this.formData[fieldName]
const hasPlaceholder =
!current || current.includes('your-lnbits-domain-here.com')
if (hasPlaceholder && calculated) {
this.formData[fieldName] = calculated
}
},
copyWebhookUrl(url) {
if (!url) {
return
}
this.copyText(url)
},
addStripeAllowedUser() {
const addUser = this.formAddStripeUser || ''
if (
@@ -26,6 +95,23 @@ window.app.component('lnbits-admin-fiat-providers', {
this.formData.stripe_limits.allowed_users =
this.formData.stripe_limits.allowed_users.filter(u => u !== user)
},
addPaypalAllowedUser() {
const addUser = this.formAddPaypalUser || ''
if (
addUser.length &&
!this.formData.paypal_limits.allowed_users.includes(addUser)
) {
this.formData.paypal_limits.allowed_users = [
...this.formData.paypal_limits.allowed_users,
addUser
]
this.formAddPaypalUser = ''
}
},
removePaypalAllowedUser(user) {
this.formData.paypal_limits.allowed_users =
this.formData.paypal_limits.allowed_users.filter(u => u !== user)
},
checkFiatProvider(providerName) {
LNbits.api
.request('PUT', `/api/v1/fiat/check/${providerName}`)