diff --git a/static/js/index.js b/static/js/index.js
index 2517657..4daad64 100644
--- a/static/js/index.js
+++ b/static/js/index.js
@@ -15,6 +15,7 @@ window.app = Vue.createApp({
users: [],
settings: null,
userWalletSettings: null,
+ userInfo: null, // User information including equity eligibility
isAdmin: false,
isSuperUser: false,
castleWalletConfigured: false,
@@ -353,6 +354,19 @@ window.app = Vue.createApp({
console.error('Error loading users:', error)
}
},
+ async loadUserInfo() {
+ try {
+ const response = await LNbits.api.request(
+ 'GET',
+ '/castle/api/v1/user/info',
+ this.g.user.wallets[0].inkey
+ )
+ this.userInfo = response.data
+ } catch (error) {
+ console.error('Error loading user info:', error)
+ this.userInfo = { is_equity_eligible: false }
+ }
+ },
async loadSettings() {
try {
// Try with admin key first to check settings
@@ -1457,6 +1471,7 @@ window.app = Vue.createApp({
// Load settings first to determine if user is super user
await this.loadSettings()
await this.loadUserWallet()
+ await this.loadUserInfo()
await this.loadExchangeRate()
await this.loadBalance()
await this.loadTransactions()
diff --git a/static/js/permissions.js b/static/js/permissions.js
index f74aa2b..4575da1 100644
--- a/static/js/permissions.js
+++ b/static/js/permissions.js
@@ -7,13 +7,19 @@ window.app = Vue.createApp({
accounts: [],
users: [],
filteredUsers: [],
+ equityEligibleUsers: [],
loading: false,
granting: false,
revoking: false,
+ grantingEquity: false,
+ revokingEquity: false,
activeTab: 'by-user',
showGrantDialog: false,
showRevokeDialog: false,
+ showGrantEquityDialog: false,
+ showRevokeEquityDialog: false,
permissionToRevoke: null,
+ equityToRevoke: null,
isSuperUser: false,
grantForm: {
user_id: '',
@@ -22,6 +28,10 @@ window.app = Vue.createApp({
notes: '',
expires_at: ''
},
+ grantEquityForm: {
+ user_id: '',
+ notes: ''
+ },
permissionTypeOptions: [
{
value: 'read',
@@ -326,6 +336,124 @@ window.app = Vue.createApp({
if (!dateString) return '-'
const date = new Date(dateString)
return date.toLocaleString()
+ },
+
+ async loadEquityEligibleUsers() {
+ if (!this.isSuperUser) {
+ return
+ }
+
+ try {
+ const response = await LNbits.api.request(
+ 'GET',
+ '/castle/api/v1/admin/equity-eligibility',
+ this.g.user.wallets[0].adminkey
+ )
+ this.equityEligibleUsers = response.data || []
+ } catch (error) {
+ console.error('Failed to load equity-eligible users:', error)
+ this.$q.notify({
+ type: 'negative',
+ message: 'Failed to load equity-eligible users',
+ caption: error.message || 'Unknown error',
+ timeout: 5000
+ })
+ }
+ },
+
+ async grantEquityEligibility() {
+ if (!this.grantEquityForm.user_id) {
+ this.$q.notify({
+ type: 'warning',
+ message: 'Please select a user',
+ timeout: 3000
+ })
+ return
+ }
+
+ this.grantingEquity = true
+ try {
+ const payload = {
+ user_id: this.grantEquityForm.user_id,
+ is_equity_eligible: true
+ }
+
+ if (this.grantEquityForm.notes) {
+ payload.notes = this.grantEquityForm.notes
+ }
+
+ await LNbits.api.request(
+ 'POST',
+ '/castle/api/v1/admin/equity-eligibility',
+ this.g.user.wallets[0].adminkey,
+ payload
+ )
+
+ this.$q.notify({
+ type: 'positive',
+ message: 'Equity eligibility granted successfully',
+ timeout: 3000
+ })
+
+ this.showGrantEquityDialog = false
+ this.resetGrantEquityForm()
+ await this.loadEquityEligibleUsers()
+ } catch (error) {
+ console.error('Failed to grant equity eligibility:', error)
+ this.$q.notify({
+ type: 'negative',
+ message: 'Failed to grant equity eligibility',
+ caption: error.message || 'Unknown error',
+ timeout: 5000
+ })
+ } finally {
+ this.grantingEquity = false
+ }
+ },
+
+ confirmRevokeEquity(equity) {
+ this.equityToRevoke = equity
+ this.showRevokeEquityDialog = true
+ },
+
+ async revokeEquityEligibility() {
+ if (!this.equityToRevoke) return
+
+ this.revokingEquity = true
+ try {
+ await LNbits.api.request(
+ 'DELETE',
+ `/castle/api/v1/admin/equity-eligibility/${this.equityToRevoke.user_id}`,
+ this.g.user.wallets[0].adminkey
+ )
+
+ this.$q.notify({
+ type: 'positive',
+ message: 'Equity eligibility revoked successfully',
+ timeout: 3000
+ })
+
+ this.showRevokeEquityDialog = false
+ this.equityToRevoke = null
+ await this.loadEquityEligibleUsers()
+ } catch (error) {
+ console.error('Failed to revoke equity eligibility:', error)
+ this.$q.notify({
+ type: 'negative',
+ message: 'Failed to revoke equity eligibility',
+ caption: error.message || 'Unknown error',
+ timeout: 5000
+ })
+ } finally {
+ this.revokingEquity = false
+ }
+ },
+
+ resetGrantEquityForm() {
+ this.grantEquityForm = {
+ user_id: '',
+ notes: ''
+ }
}
},
@@ -338,7 +466,8 @@ window.app = Vue.createApp({
if (this.isSuperUser) {
await Promise.all([
this.loadPermissions(),
- this.loadUsers()
+ this.loadUsers(),
+ this.loadEquityEligibleUsers()
])
}
}
diff --git a/templates/castle/index.html b/templates/castle/index.html
index c907303..86613e7 100644
--- a/templates/castle/index.html
+++ b/templates/castle/index.html
@@ -723,6 +723,7 @@
>
No equity-eligible users yet
+Are you sure you want to revoke equity eligibility for this user?
++ Note: This will prevent them from adding new expenses as equity contributions. + Their existing equity account and contributions will remain unchanged. +
+