Initial commit: Premier Gunner tracker + StartOS 0.4.0 s9pk package
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import { db } from '../db.js';
|
||||
|
||||
function categoriesWithMetrics({ includeArchived = false } = {}) {
|
||||
const cats = db.prepare(
|
||||
`SELECT * FROM categories ${includeArchived ? '' : 'WHERE archived = 0'} ORDER BY sort_order, id`
|
||||
).all();
|
||||
const metrics = db.prepare('SELECT * FROM category_metrics ORDER BY sort_order, id').all();
|
||||
const byCat = new Map();
|
||||
for (const m of metrics) {
|
||||
if (!byCat.has(m.category_id)) byCat.set(m.category_id, []);
|
||||
byCat.get(m.category_id).push(m);
|
||||
}
|
||||
return cats.map((c) => ({ ...c, metrics: byCat.get(c.id) || [] }));
|
||||
}
|
||||
|
||||
export { categoriesWithMetrics };
|
||||
|
||||
export default async function categoryRoutes(app) {
|
||||
app.get('/api/categories', async (req) => {
|
||||
const includeArchived = req.query?.all === '1';
|
||||
return categoriesWithMetrics({ includeArchived });
|
||||
});
|
||||
|
||||
app.post('/api/categories', async (req, reply) => {
|
||||
const { name, emoji, color, metrics } = req.body || {};
|
||||
if (!name) return reply.code(400).send({ error: 'Name required' });
|
||||
const maxOrder = db.prepare('SELECT COALESCE(MAX(sort_order), -1) AS m FROM categories').get().m;
|
||||
const result = db.prepare(
|
||||
'INSERT INTO categories (name, emoji, color, sort_order) VALUES (?, ?, ?, ?)'
|
||||
).run(name, emoji || '⚽', color || '#EF0107', maxOrder + 1);
|
||||
const catId = result.lastInsertRowid;
|
||||
const list = Array.isArray(metrics) && metrics.length
|
||||
? metrics
|
||||
: [{ name: 'Minutes', unit: 'min', kind: 'duration', step: 5 }];
|
||||
list.forEach((m, i) => {
|
||||
db.prepare(
|
||||
'INSERT INTO category_metrics (category_id, name, unit, kind, step, higher_is_better, sort_order) ' +
|
||||
'VALUES (?, ?, ?, ?, ?, ?, ?)'
|
||||
).run(catId, m.name || 'Value', m.unit || '', m.kind || 'count', m.step || 1, m.higher_is_better ?? 1, i);
|
||||
});
|
||||
return categoriesWithMetrics({ includeArchived: true }).find((c) => c.id === Number(catId));
|
||||
});
|
||||
|
||||
app.put('/api/categories/:id', async (req, reply) => {
|
||||
const id = Number(req.params.id);
|
||||
const cat = db.prepare('SELECT * FROM categories WHERE id = ?').get(id);
|
||||
if (!cat) return reply.code(404).send({ error: 'Not found' });
|
||||
const { name, emoji, color, archived } = req.body || {};
|
||||
db.prepare(
|
||||
'UPDATE categories SET name = ?, emoji = ?, color = ?, archived = ? WHERE id = ?'
|
||||
).run(name ?? cat.name, emoji ?? cat.emoji, color ?? cat.color,
|
||||
archived !== undefined ? (archived ? 1 : 0) : cat.archived, id);
|
||||
return categoriesWithMetrics({ includeArchived: true }).find((c) => c.id === id);
|
||||
});
|
||||
|
||||
// Add a metric to an existing category.
|
||||
app.post('/api/categories/:id/metrics', async (req, reply) => {
|
||||
const id = Number(req.params.id);
|
||||
const cat = db.prepare('SELECT id FROM categories WHERE id = ?').get(id);
|
||||
if (!cat) return reply.code(404).send({ error: 'Not found' });
|
||||
const { name, unit, kind, step, higher_is_better } = req.body || {};
|
||||
const maxOrder = db.prepare(
|
||||
'SELECT COALESCE(MAX(sort_order), -1) AS m FROM category_metrics WHERE category_id = ?'
|
||||
).get(id).m;
|
||||
db.prepare(
|
||||
'INSERT INTO category_metrics (category_id, name, unit, kind, step, higher_is_better, sort_order) ' +
|
||||
'VALUES (?, ?, ?, ?, ?, ?, ?)'
|
||||
).run(id, name || 'Value', unit || '', kind || 'count', step || 1, higher_is_better ?? 1, maxOrder + 1);
|
||||
return categoriesWithMetrics({ includeArchived: true }).find((c) => c.id === id);
|
||||
});
|
||||
|
||||
app.delete('/api/metrics/:id', async (req, reply) => {
|
||||
const id = Number(req.params.id);
|
||||
db.prepare('DELETE FROM category_metrics WHERE id = ?').run(id);
|
||||
return reply.send({ ok: true });
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user