/*! * Tectum * Copyright © 2026 Machiel Heinen. * Alle rechten voorbehouden. Gebruik uitsluitend met schriftelijke toestemming. * Zie LICENTIE.md. */ // ============================================================ // cost/cost-settings.js — CostSettings: venster "Kosten & tijden". Bouwt // het formulier automatisch uit COST_DEFAULTS (elk item een invoerveld), // opslaan via CostModel.saveSettings (localStorage). Exporteren/importeren // als JSON-bestand; "Standaard" zet alle velden terug op cost-defaults.js. // Alleen UI; de rekenregels staan in CostModel. // ============================================================ window.CostSettings = (() => { let overlay = null; const esc = UI.esc; function build() { overlay = document.createElement('div'); overlay.id = 'cost-settings-overlay'; overlay.innerHTML = `
Bedragen excl. btw. Opslaan bewaart in deze browser én downloadt een JSON-bestand; een gewijzigd veld is gemarkeerd. Standaardwaarden staan in js/cost/cost-defaults.js.
`; document.body.appendChild(overlay); overlay.addEventListener('click', (e) => { if (e.target === overlay) return close(); const btn = e.target.closest('[data-cs]'); if (!btn) return; const a = btn.dataset.cs; if (a === 'cancel') close(); else if (a === 'save') { // ook als JSON-bestand (om te delen/bewaren) const v = readForm(); CostModel.saveSettings(v); download(CostModel.exportJson(v)); close(); } else if (a === 'reset') fill(CostModel.defaultValues()); else if (a === 'export') download(CostModel.exportJson(readForm())); else if (a === 'import') overlay.querySelector('input[type=file]').click(); }); overlay.addEventListener('input', markChanged); overlay.querySelector('input[type=file]').addEventListener('change', (e) => { const file = e.target.files[0]; e.target.value = ''; if (!file) return; file.text().then(txt => fill(CostModel.importJson(JSON.parse(txt)))) .catch(err => alert('Importeren mislukt: ' + err.message)); }); } function renderForm() { const body = overlay.querySelector('.cs-body'); body.innerHTML = Object.entries(window.COST_DEFAULTS).map(([g, grp]) => `

${esc(grp.label)}

${Object.entries(grp.items).map(([k, it]) => ` `).join('')}
`).join(''); } function fill(values) { overlay.querySelectorAll('[data-g]').forEach(el => { el.value = values[el.dataset.g][el.dataset.k]; }); markChanged(); } function readForm() { const v = CostModel.getSettings(); overlay.querySelectorAll('[data-g]').forEach(el => { const it = window.COST_DEFAULTS[el.dataset.g].items[el.dataset.k]; const val = it.options ? el.value : parseFloat(el.value); if (it.options || isFinite(val)) v[el.dataset.g][el.dataset.k] = val; }); return v; } // Afwijkend van de standaard: gemarkeerd. function markChanged() { const def = CostModel.defaultValues(); overlay.querySelectorAll('[data-g]').forEach(el => { const d = def[el.dataset.g][el.dataset.k]; el.closest('.cs-row').classList.toggle('changed', typeof d === 'number' ? parseFloat(el.value) !== d : el.value !== d); }); } function download(obj) { const blob = new Blob([JSON.stringify(obj, null, 2)], { type: 'application/json' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `tectum-kosten-${new Date().toISOString().slice(0, 10)}.json`; a.click(); setTimeout(() => URL.revokeObjectURL(a.href), 1000); } function open() { if (!overlay) build(); renderForm(); // opnieuw: nieuwe items in cost-defaults.js verschijnen vanzelf fill(CostModel.getSettings()); overlay.classList.add('open'); } function close() { if (overlay) overlay.classList.remove('open'); } return { open, close }; })();