const express = require('express'); const router = express.Router(); const { getDb, ensureUserDefaultCategories } = require('../db/database'); // GET /api/categories router.get('/', (req, res) => { const db = getDb(); ensureUserDefaultCategories(req.user.id); const categories = db.prepare(` SELECT id, user_id, name, created_at, updated_at FROM categories WHERE user_id = ? ORDER BY name COLLATE NOCASE ASC `).all(req.user.id); const billsByCategory = db.prepare(` SELECT b.id, b.category_id, b.name, b.active, b.expected_amount, b.due_day, COUNT(p.id) AS payment_count, COALESCE(SUM(p.amount), 0) AS total_paid, MAX(p.paid_date) AS last_paid_date FROM bills b LEFT JOIN payments p ON p.bill_id = b.id AND p.deleted_at IS NULL WHERE b.user_id = ? AND b.category_id = ? GROUP BY b.id ORDER BY b.active DESC, b.due_day ASC, b.name COLLATE NOCASE ASC `); const shaped = categories.map(category => { const bills = billsByCategory.all(req.user.id, category.id).map(bill => ({ ...bill, active: !!bill.active, payment_count: Number(bill.payment_count || 0), total_paid: Number(bill.total_paid || 0), last_paid_date: bill.last_paid_date || null, })); const activeBillCount = bills.filter(bill => bill.active).length; const inactiveBillCount = bills.length - activeBillCount; const paymentCount = bills.reduce((sum, bill) => sum + bill.payment_count, 0); return { ...category, bill_count: activeBillCount, active_bill_count: activeBillCount, inactive_bill_count: inactiveBillCount, payment_count: paymentCount, bill_names: bills.map(bill => bill.name), bills, }; }); res.json(shaped); }); // POST /api/categories router.post('/', (req, res) => { const db = getDb(); const { name } = req.body; if (!name) return res.status(400).json({ error: 'name is required' }); try { const result = db.prepare('INSERT INTO categories (user_id, name) VALUES (?, ?)').run(req.user.id, name.trim()); const created = db.prepare('SELECT * FROM categories WHERE id = ?').get(result.lastInsertRowid); res.status(201).json(created); } catch (e) { if (e.message.includes('UNIQUE')) { return res.status(409).json({ error: 'Category already exists' }); } throw e; } }); // PUT /api/categories/:id router.put('/:id', (req, res) => { const db = getDb(); const { name } = req.body; if (!name) return res.status(400).json({ error: 'name is required' }); const cat = db.prepare('SELECT id FROM categories WHERE id = ? AND user_id = ?').get(req.params.id, req.user.id); if (!cat) return res.status(404).json({ error: 'Category not found' }); try { db.prepare("UPDATE categories SET name = ?, updated_at = datetime('now') WHERE id = ? AND user_id = ?") .run(name.trim(), req.params.id, req.user.id); res.json(db.prepare('SELECT * FROM categories WHERE id = ? AND user_id = ?').get(req.params.id, req.user.id)); } catch (e) { if (e.message.includes('UNIQUE')) { return res.status(409).json({ error: 'Category already exists' }); } throw e; } }); // DELETE /api/categories/:id router.delete('/:id', (req, res) => { const db = getDb(); const cat = db.prepare('SELECT id FROM categories WHERE id = ? AND user_id = ?').get(req.params.id, req.user.id); if (!cat) return res.status(404).json({ error: 'Category not found' }); db.prepare('DELETE FROM categories WHERE id = ? AND user_id = ?').run(req.params.id, req.user.id); res.json({ success: true }); }); module.exports = router;