feat: event proposal and approval workflow #9
2 changed files with 131 additions and 2 deletions
feat: add pending approvals UI to admin panel
Some checks failed
lint.yml / feat: add pending approvals UI to admin panel (pull_request) Failing after 0s
Some checks failed
lint.yml / feat: add pending approvals UI to admin panel (pull_request) Failing after 0s
- Separate "Pending Approvals" card with approve/reject buttons (appears only when proposed events exist) - Status badge column in events table (green/orange/red) - Inline approve/reject buttons on proposed events in table - Following castle extension's approval UI pattern Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
commit
702ab70559
|
|
@ -73,7 +73,8 @@ window.app = Vue.createApp({
|
||||||
field: 'sold'
|
field: 'sold'
|
||||||
},
|
},
|
||||||
{name: 'info', align: 'left', label: 'Info', field: 'info'},
|
{name: 'info', align: 'left', label: 'Info', field: 'info'},
|
||||||
{name: 'banner', align: 'left', label: 'Banner', field: 'banner'}
|
{name: 'banner', align: 'left', label: 'Banner', field: 'banner'},
|
||||||
|
{name: 'status', align: 'left', label: 'Status', field: 'status'}
|
||||||
],
|
],
|
||||||
pagination: {
|
pagination: {
|
||||||
rowsPerPage: 10
|
rowsPerPage: 10
|
||||||
|
|
@ -112,7 +113,56 @@ window.app = Vue.createApp({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
pendingEvents() {
|
||||||
|
return this.events.filter(e => e.status === 'proposed')
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
approveEvent(eventId) {
|
||||||
|
LNbits.utils
|
||||||
|
.confirmDialog('Approve this event?')
|
||||||
|
.onOk(() => {
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'PUT',
|
||||||
|
'/events/api/v1/events/' + eventId + '/approve',
|
||||||
|
this.g.user.wallets[0].adminkey
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
this.$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
message: 'Event approved'
|
||||||
|
})
|
||||||
|
this.getEvents()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
LNbits.utils.notifyApiError(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
rejectEvent(eventId) {
|
||||||
|
LNbits.utils
|
||||||
|
.confirmDialog('Reject this event?')
|
||||||
|
.onOk(() => {
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'PUT',
|
||||||
|
'/events/api/v1/events/' + eventId + '/reject',
|
||||||
|
this.g.user.wallets[0].adminkey
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
this.$q.notify({
|
||||||
|
type: 'positive',
|
||||||
|
message: 'Event rejected'
|
||||||
|
})
|
||||||
|
this.getEvents()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
LNbits.utils.notifyApiError(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
getTickets() {
|
getTickets() {
|
||||||
LNbits.api
|
LNbits.api
|
||||||
.request(
|
.request(
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,58 @@
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
||||||
|
<!-- Pending Event Approvals -->
|
||||||
|
<q-card v-if="pendingEvents.length > 0">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="row items-center no-wrap q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<h5 class="text-subtitle1 q-my-none">
|
||||||
|
<q-icon name="pending" color="orange" class="q-mr-sm" />
|
||||||
|
Pending Approvals
|
||||||
|
<q-badge color="orange" :label="pendingEvents.length" class="q-ml-sm" />
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<q-list separator>
|
||||||
|
<q-item v-for="event in pendingEvents" :key="event.id">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{% raw %}{{ event.name }}{% endraw %}</q-item-label>
|
||||||
|
<q-item-label caption>
|
||||||
|
{% raw %}{{ event.event_start_date }}{% endraw %}
|
||||||
|
—
|
||||||
|
{% raw %}{{ event.info.substring(0, 80) }}{% endraw %}{% raw %}{{ event.info.length > 80 ? '...' : '' }}{% endraw %}
|
||||||
|
</q-item-label>
|
||||||
|
<q-item-label caption>
|
||||||
|
{% raw %}{{ event.amount_tickets }}{% endraw %} tickets •
|
||||||
|
{% raw %}{{ event.price_per_ticket }}{% endraw %} {% raw %}{{ event.currency }}{% endraw %}
|
||||||
|
</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section side>
|
||||||
|
<div class="row q-gutter-sm">
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
color="green"
|
||||||
|
icon="check_circle"
|
||||||
|
label="Approve"
|
||||||
|
size="sm"
|
||||||
|
@click="approveEvent(event.id)"
|
||||||
|
/>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
outline
|
||||||
|
color="red"
|
||||||
|
icon="block"
|
||||||
|
label="Reject"
|
||||||
|
size="sm"
|
||||||
|
@click="rejectEvent(event.id)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<div class="row items-center no-wrap q-mb-md">
|
<div class="row items-center no-wrap q-mb-md">
|
||||||
|
|
@ -76,9 +128,36 @@
|
||||||
></q-btn>
|
></q-btn>
|
||||||
</q-td>
|
</q-td>
|
||||||
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
<span v-text="col.value"></span>
|
<q-badge
|
||||||
|
v-if="col.name === 'status'"
|
||||||
|
:color="col.value === 'approved' ? 'green' : col.value === 'proposed' ? 'orange' : 'red'"
|
||||||
|
:label="col.value"
|
||||||
|
/>
|
||||||
|
<span v-else v-text="col.value"></span>
|
||||||
</q-td>
|
</q-td>
|
||||||
<q-td auto-width>
|
<q-td auto-width>
|
||||||
|
<q-btn
|
||||||
|
v-if="props.row.status === 'proposed'"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
size="xs"
|
||||||
|
@click="approveEvent(props.row.id)"
|
||||||
|
icon="check_circle"
|
||||||
|
color="green"
|
||||||
|
>
|
||||||
|
<q-tooltip>Approve</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
<q-btn
|
||||||
|
v-if="props.row.status === 'proposed'"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
size="xs"
|
||||||
|
@click="rejectEvent(props.row.id)"
|
||||||
|
icon="block"
|
||||||
|
color="red"
|
||||||
|
>
|
||||||
|
<q-tooltip>Reject</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
<q-btn
|
<q-btn
|
||||||
flat
|
flat
|
||||||
dense
|
dense
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue