Add edit and delete to task modal

Edit button (update cap): inline form for title, description, priority, unusable flag, due date. Delete button (admin only): hard delete with confirm step, cascades photos/events and cleans files from disk. Backend adds DELETE /api/tasks/:id route.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-22 10:17:57 +00:00
parent 03d1cd2bb6
commit ca006f9aea
3 changed files with 118 additions and 5 deletions

View file

@ -4,6 +4,11 @@ import { createTask, logEvent, TRANSITIONS, PRIORITIES, STATUSES } from '../lib/
import { fetchBookings } from '../lib/newbook.js'
import { notifyAssignment } from '../lib/mailer.js'
import { notifyAssignmentPush } from '../lib/push.js'
import { unlink } from 'fs/promises'
import { fileURLToPath } from 'url'
import { dirname, join } from 'path'
const UPLOADS_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'uploads')
const PRIORITY_ORDER = `CASE t.priority WHEN 'urgent' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 ELSE 3 END`
@ -222,6 +227,18 @@ export async function taskRoutes(app) {
return rows[0]
})
// DELETE /api/tasks/:id — hard delete; photo files removed from disk; events/photos cascade
app.delete('/api/tasks/:id', { preHandler: requireCap('update') }, async (req, reply) => {
const { rows: existing } = await pool.query('SELECT id FROM tasks WHERE id = $1', [req.params.id])
if (!existing.length) return reply.status(404).send({ error: 'Task not found' })
const taskId = existing[0].id
const { rows: photos } = await pool.query('SELECT file_path FROM task_photos WHERE task_id = $1', [taskId])
await pool.query('DELETE FROM tasks WHERE id = $1', [taskId])
for (const p of photos) await unlink(join(UPLOADS_DIR, p.file_path)).catch(() => {})
return { ok: true }
})
// POST /api/tasks/:id/resolve — temporary_fix or fixed, with completed-by and cost
app.post('/api/tasks/:id/resolve', { preHandler: requireCap('resolve') }, async (req, reply) => {
const b = req.body || {}