Move general tasks + time reqs to Settings; add date adjustments

- Rename 'Category Settings' to 'Settings' (nav, page title, component)
- Move Recurring General Tasks and Time Requirements editing to Settings page
- Planner still loads both for calcRequired calculations
- Add date-specific Adjustments section to Planner: per-date +/- hour
  offsets keyed by YYYY-MM-DD (non-recurring); feed into Required Hours total
- Adjustments row shown in Required Hours tfoot when non-zero

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-07 21:11:21 +00:00
parent b803b01ae1
commit c0b1d2a62e
7 changed files with 416 additions and 238 deletions

View file

@ -8,7 +8,7 @@ export async function configRoutes(app) {
// ── GET /api/config — all settings at once ──────────────────────────────
app.get('/api/config', async (req) => {
const [timeReqs, staffData, pickupData, generalTasks, lastReviewed, toleranceMins, workforceRota, workforceDepts] =
const [timeReqs, staffData, pickupData, generalTasks, lastReviewed, toleranceMins, workforceRota, workforceDepts, adjustments] =
await Promise.all([
getConfig('time_requirements', {}),
getConfig('staff_data', []),
@ -18,6 +18,7 @@ export async function configRoutes(app) {
getConfig('tolerance_minutes', 30),
getConfig('workforce_rota', null),
getConfig('workforce_departments', []),
getConfig('adjustments', []),
])
const today = new Date()
@ -35,6 +36,7 @@ export async function configRoutes(app) {
tolerance_minutes: toleranceMins != null ? toleranceMins : 30,
workforce_rota: workforceRota || null,
workforce_departments: workforceDepts || [],
adjustments: adjustments || [],
}
})
@ -138,6 +140,27 @@ export async function configRoutes(app) {
return { ok: true }
})
// ── PUT /api/config/adjustments ──────────────────────────────────────────
app.put('/api/config/adjustments', async (req, reply) => {
const { adjustments } = req.body || {}
if (!Array.isArray(adjustments)) return reply.status(400).send({ error: 'Invalid data' })
const clean = adjustments
.filter(a => a && typeof a.label === 'string')
.map(a => ({
label: a.label.trim(),
hours: Object.fromEntries(
Object.entries(a.hours || {})
.filter(([k]) => /^\d{4}-\d{2}-\d{2}$/.test(k))
.map(([k, v]) => [k, parseFloat(v) || 0])
),
}))
await setConfig('adjustments', clean)
return { ok: true }
})
// ── GET /api/categories — settings cap required ──────────────────────────
app.get('/api/categories', { preHandler: requireCap('settings') }, async (req, reply) => {