diff --git a/package.json b/package.json index 23cbf13..22c2e57 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "test:shopping": "node --experimental-sqlite test-shopping.js", "test:meals": "node --experimental-sqlite test-meals.js", "test:calendar": "node --experimental-sqlite test-calendar.js", - "test": "node --experimental-sqlite test-db.js && node --experimental-sqlite test-dashboard.js && node --experimental-sqlite test-tasks.js && node --experimental-sqlite test-shopping.js && node --experimental-sqlite test-meals.js && node --experimental-sqlite test-calendar.js" + "test:ncb": "node --experimental-sqlite test-notes-contacts-budget.js", + "test": "node --experimental-sqlite test-db.js && node --experimental-sqlite test-dashboard.js && node --experimental-sqlite test-tasks.js && node --experimental-sqlite test-shopping.js && node --experimental-sqlite test-meals.js && node --experimental-sqlite test-calendar.js && node --experimental-sqlite test-notes-contacts-budget.js" }, "dependencies": { "bcrypt": "^5.1.1", diff --git a/public/index.html b/public/index.html index 0c15883..e143b29 100644 --- a/public/index.html +++ b/public/index.html @@ -21,6 +21,9 @@ + + + diff --git a/public/pages/budget.js b/public/pages/budget.js index 744c130..c961e13 100644 --- a/public/pages/budget.js +++ b/public/pages/budget.js @@ -1,25 +1,437 @@ /** - * Modul: Budget - * Zweck: Seite für das Budget-Modul - * Abhängigkeiten: /api.js + * Modul: Budget-Tracker (Budget) + * Zweck: Monatsübersicht, Kategorie-Balkendiagramm (Canvas), Transaktionsliste, + * CRUD, CSV-Export + * Abhängigkeiten: /api.js, /router.js (window.oikos) */ import { api } from '/api.js'; -/** - * @param {HTMLElement} container - * @param {{ user: object }} context - */ +// -------------------------------------------------------- +// Konstanten +// -------------------------------------------------------- + +const CATEGORIES = [ + 'Lebensmittel', 'Miete', 'Versicherung', 'Mobilität', + 'Freizeit', 'Kleidung', 'Gesundheit', 'Bildung', 'Sonstiges', +]; + +const MONTH_NAMES = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', + 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember']; + +// -------------------------------------------------------- +// State +// -------------------------------------------------------- + +let state = { + month: '', // YYYY-MM + entries: [], + summary: null, +}; + +// -------------------------------------------------------- +// Formatierung +// -------------------------------------------------------- + +function formatAmount(n) { + return new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(n); +} + +function formatMonthLabel(ym) { + const [y, m] = ym.split('-'); + return `${MONTH_NAMES[parseInt(m, 10) - 1]} ${y}`; +} + +function addMonths(ym, n) { + const [y, m] = ym.split('-').map(Number); + const d = new Date(y, m - 1 + n, 1); + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`; +} + +// -------------------------------------------------------- +// API +// -------------------------------------------------------- + +async function loadMonth(month) { + const [entriesRes, summaryRes] = await Promise.all([ + api.get(`/budget?month=${month}`), + api.get(`/budget/summary?month=${month}`), + ]); + state.month = month; + state.entries = entriesRes.data; + state.summary = summaryRes.data; +} + +// -------------------------------------------------------- +// Entry Point +// -------------------------------------------------------- + export async function render(container, { user }) { + const today = new Date(); + state.month = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}`; + container.innerHTML = ` -
-