views_api wires the full task lifecycle: create / update / delete / list (per-wallet, public, admin-all) and the completion flow (claim / start / complete via POST, unclaim via DELETE, plus a "mine" lookup for the current user's claim on a task or specific occurrence). Auth model: tasks are owned by an LNbits wallet but signed with the wallet owner's account.pubkey — _wallet_pubkey resolves that pubkey at create time and refuses to create tasks for accounts that haven't generated a keypair yet, so we never publish a task we can't sign. Completions optimistically insert with a local hash, publish to Nostr, then re-insert under the actual event id so a later delete can find it. Static SPA: Quasar-UMD index.vue / index.js mirroring the events extension layout — wallet picker, task table, create/edit dialog with optional daily/weekly recurrence, plus an admin-only public_listing toggle. /tasks/:id and display.vue intentionally left out until the public task page lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
192 lines
5 KiB
JavaScript
192 lines
5 KiB
JavaScript
window.PageTasks = {
|
|
template: '#page-tasks',
|
|
data() {
|
|
return {
|
|
tasks: [],
|
|
isAdmin: false,
|
|
settings: {
|
|
public_listing: false
|
|
},
|
|
tasksTable: {
|
|
columns: [
|
|
{name: 'title', align: 'left', label: 'Title', field: 'title'},
|
|
{
|
|
name: 'start_date',
|
|
align: 'left',
|
|
label: 'Start',
|
|
field: 'start_date'
|
|
},
|
|
{
|
|
name: 'end_date',
|
|
align: 'left',
|
|
label: 'End',
|
|
field: 'end_date'
|
|
},
|
|
{
|
|
name: 'recurrence',
|
|
align: 'left',
|
|
label: 'Recurrence',
|
|
field: row => (row.recurrence ? row.recurrence.frequency : '')
|
|
},
|
|
{name: 'status', align: 'left', label: 'Status', field: 'status'},
|
|
{name: 'location', align: 'left', label: 'Location', field: 'location'}
|
|
],
|
|
pagination: {
|
|
rowsPerPage: 10
|
|
}
|
|
},
|
|
taskDialog: {
|
|
show: false,
|
|
data: {}
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
canSubmit() {
|
|
return (
|
|
this.taskDialog.data.title &&
|
|
this.taskDialog.data.start_date &&
|
|
this.taskDialog.data.wallet
|
|
)
|
|
}
|
|
},
|
|
methods: {
|
|
openTaskDialog() {
|
|
this.taskDialog.data = {
|
|
title: '',
|
|
start_date: '',
|
|
end_date: '',
|
|
description: '',
|
|
location: '',
|
|
wallet: this.g.user.wallets[0]?.id,
|
|
recurrence_frequency: '',
|
|
recurrence_day_of_week: '',
|
|
recurrence_end_date: ''
|
|
}
|
|
this.taskDialog.show = true
|
|
},
|
|
editTask(row) {
|
|
this.taskDialog.data = {
|
|
id: row.id,
|
|
wallet: row.wallet,
|
|
title: row.title,
|
|
start_date: row.start_date,
|
|
end_date: row.end_date || '',
|
|
description: row.description || '',
|
|
location: row.location || '',
|
|
recurrence_frequency: row.recurrence?.frequency || '',
|
|
recurrence_day_of_week: row.recurrence?.day_of_week || '',
|
|
recurrence_end_date: row.recurrence?.end_date || ''
|
|
}
|
|
this.taskDialog.show = true
|
|
},
|
|
_buildPayload(d) {
|
|
const payload = {
|
|
wallet: d.wallet,
|
|
title: d.title,
|
|
start_date: d.start_date,
|
|
end_date: d.end_date || null,
|
|
description: d.description || '',
|
|
location: d.location || null
|
|
}
|
|
if (d.recurrence_frequency) {
|
|
payload.recurrence = {
|
|
frequency: d.recurrence_frequency,
|
|
day_of_week: d.recurrence_day_of_week || null,
|
|
end_date: d.recurrence_end_date || null
|
|
}
|
|
}
|
|
return payload
|
|
},
|
|
async submitTask() {
|
|
const d = this.taskDialog.data
|
|
const wallet = _.findWhere(this.g.user.wallets, {id: d.wallet})
|
|
if (!wallet) return
|
|
const payload = this._buildPayload(d)
|
|
try {
|
|
if (d.id) {
|
|
await LNbits.api.request(
|
|
'PUT',
|
|
'/tasks/api/v1/tasks/' + d.id,
|
|
wallet.adminkey,
|
|
payload
|
|
)
|
|
} else {
|
|
await LNbits.api.request(
|
|
'POST',
|
|
'/tasks/api/v1/tasks',
|
|
wallet.adminkey,
|
|
payload
|
|
)
|
|
}
|
|
this.taskDialog.show = false
|
|
this.getTasks()
|
|
} catch (error) {
|
|
LNbits.utils.notifyApiError(error)
|
|
}
|
|
},
|
|
async deleteTask(taskId) {
|
|
LNbits.utils
|
|
.confirmDialog('Delete this task?')
|
|
.onOk(async () => {
|
|
const task = _.findWhere(this.tasks, {id: taskId})
|
|
const wallet = _.findWhere(this.g.user.wallets, {id: task.wallet})
|
|
if (!wallet) return
|
|
try {
|
|
await LNbits.api.request(
|
|
'DELETE',
|
|
'/tasks/api/v1/tasks/' + taskId,
|
|
wallet.adminkey
|
|
)
|
|
this.getTasks()
|
|
} catch (error) {
|
|
LNbits.utils.notifyApiError(error)
|
|
}
|
|
})
|
|
},
|
|
async getTasks() {
|
|
try {
|
|
const wallet = this.g.user.wallets[0]
|
|
if (!wallet) return
|
|
const {data} = await LNbits.api.request(
|
|
'GET',
|
|
'/tasks/api/v1/tasks?all_wallets=true',
|
|
wallet.inkey
|
|
)
|
|
this.tasks = data
|
|
} catch (error) {
|
|
LNbits.utils.notifyApiError(error)
|
|
}
|
|
},
|
|
async getSettings() {
|
|
if (!this.isAdmin) return
|
|
try {
|
|
const {data} = await LNbits.api.request(
|
|
'GET',
|
|
'/tasks/api/v1/tasks/settings',
|
|
this.g.user.wallets[0]?.adminkey
|
|
)
|
|
this.settings = data
|
|
} catch (_) {
|
|
// Non-admin or settings not seeded — silent.
|
|
}
|
|
},
|
|
async saveSettings() {
|
|
try {
|
|
await LNbits.api.request(
|
|
'PUT',
|
|
'/tasks/api/v1/tasks/settings',
|
|
this.g.user.wallets[0]?.adminkey,
|
|
this.settings
|
|
)
|
|
} catch (error) {
|
|
LNbits.utils.notifyApiError(error)
|
|
}
|
|
}
|
|
},
|
|
created() {
|
|
this.isAdmin = !!(window.user && window.user.admin)
|
|
this.getTasks()
|
|
this.getSettings()
|
|
}
|
|
}
|