castle/static/js/index.js
padreug 29983cedb7 Adds user settings for the Castle extension
Adds functionality to configure the Castle extension, including a wallet ID.

This allows administrators to customize the extension's behavior by specifying a dedicated wallet for castle operations.
2025-10-22 13:55:52 +02:00

241 lines
6.5 KiB
JavaScript

const mapJournalEntry = obj => {
return obj
}
window.app = Vue.createApp({
el: '#vue',
mixins: [windowMixin],
data() {
return {
balance: null,
transactions: [],
accounts: [],
currencies: [],
settings: null,
isAdmin: false,
expenseDialog: {
show: false,
description: '',
amount: null,
expenseAccount: '',
isEquity: false,
reference: '',
currency: null,
loading: false
},
payDialog: {
show: false,
amount: null,
loading: false
},
settingsDialog: {
show: false,
castleWalletId: '',
loading: false
}
}
},
computed: {
expenseAccounts() {
return this.accounts.filter(a => a.account_type === 'expense')
},
amountLabel() {
if (this.expenseDialog.currency) {
return `Amount (${this.expenseDialog.currency}) *`
}
return 'Amount (sats) *'
},
currencyOptions() {
const options = [{label: 'Satoshis (default)', value: null}]
this.currencies.forEach(curr => {
options.push({label: curr, value: curr})
})
return options
}
},
methods: {
async loadBalance() {
try {
const response = await LNbits.api.request(
'GET',
'/castle/api/v1/balance',
this.g.user.wallets[0].inkey
)
this.balance = response.data
} catch (error) {
LNbits.utils.notifyApiError(error)
}
},
async loadTransactions() {
try {
const response = await LNbits.api.request(
'GET',
'/castle/api/v1/entries/user',
this.g.user.wallets[0].inkey
)
this.transactions = response.data
} catch (error) {
LNbits.utils.notifyApiError(error)
}
},
async loadAccounts() {
try {
const response = await LNbits.api.request(
'GET',
'/castle/api/v1/accounts',
this.g.user.wallets[0].inkey
)
this.accounts = response.data
} catch (error) {
LNbits.utils.notifyApiError(error)
}
},
async loadCurrencies() {
try {
const response = await LNbits.api.request(
'GET',
'/castle/api/v1/currencies',
this.g.user.wallets[0].inkey
)
this.currencies = response.data
} catch (error) {
LNbits.utils.notifyApiError(error)
}
},
async loadSettings() {
try {
const response = await LNbits.api.request(
'GET',
'/castle/api/v1/settings',
this.g.user.wallets[0].adminkey
)
this.settings = response.data
this.isAdmin = true
} catch (error) {
// Not admin or settings not available
this.isAdmin = false
}
},
showSettingsDialog() {
this.settingsDialog.castleWalletId = this.settings?.castle_wallet_id || ''
this.settingsDialog.show = true
},
async submitSettings() {
this.settingsDialog.loading = true
try {
await LNbits.api.request(
'PUT',
'/castle/api/v1/settings',
this.g.user.wallets[0].adminkey,
{
castle_wallet_id: this.settingsDialog.castleWalletId
}
)
this.$q.notify({
type: 'positive',
message: 'Settings updated successfully'
})
this.settingsDialog.show = false
await this.loadSettings()
} catch (error) {
LNbits.utils.notifyApiError(error)
} finally {
this.settingsDialog.loading = false
}
},
async submitExpense() {
this.expenseDialog.loading = true
try {
await LNbits.api.request(
'POST',
'/castle/api/v1/entries/expense',
this.g.user.wallets[0].inkey,
{
description: this.expenseDialog.description,
amount: this.expenseDialog.amount,
expense_account: this.expenseDialog.expenseAccount,
is_equity: this.expenseDialog.isEquity,
user_wallet: this.g.user.wallets[0].id,
reference: this.expenseDialog.reference || null,
currency: this.expenseDialog.currency || null
}
)
this.$q.notify({
type: 'positive',
message: 'Expense added successfully'
})
this.expenseDialog.show = false
this.resetExpenseDialog()
await this.loadBalance()
await this.loadTransactions()
} catch (error) {
LNbits.utils.notifyApiError(error)
} finally {
this.expenseDialog.loading = false
}
},
async submitPayment() {
this.payDialog.loading = true
try {
// First, generate an invoice for the payment
const invoiceResponse = await LNbits.api.request(
'POST',
'/api/v1/payments',
this.g.user.wallets[0].inkey,
{
out: false,
amount: this.payDialog.amount,
memo: `Payment to Castle - ${this.payDialog.amount} sats`,
unit: 'sat'
}
)
// Show the invoice to the user
this.$q.notify({
type: 'positive',
message: 'Invoice generated! Pay it to settle your balance.',
timeout: 5000
})
// TODO: After payment, call /castle/api/v1/pay-balance to record it
// This would typically be done via a webhook or payment verification
this.payDialog.show = false
this.payDialog.amount = null
} catch (error) {
LNbits.utils.notifyApiError(error)
} finally {
this.payDialog.loading = false
}
},
showPayBalanceDialog() {
this.payDialog.amount = Math.abs(this.balance.balance)
this.payDialog.show = true
},
resetExpenseDialog() {
this.expenseDialog.description = ''
this.expenseDialog.amount = null
this.expenseDialog.expenseAccount = ''
this.expenseDialog.isEquity = false
this.expenseDialog.reference = ''
this.expenseDialog.currency = null
},
formatSats(amount) {
return new Intl.NumberFormat().format(amount)
},
formatDate(dateString) {
return new Date(dateString).toLocaleDateString()
},
getTotalAmount(entry) {
if (!entry.lines || entry.lines.length === 0) return 0
return entry.lines.reduce((sum, line) => sum + line.debit + line.credit, 0) / 2
}
},
async created() {
await this.loadBalance()
await this.loadTransactions()
await this.loadAccounts()
await this.loadCurrencies()
await this.loadSettings()
}
})