(() => { const root = document.getElementById('fx-rates-app'); if (!root) { return; } const page = JSON.parse(root.dataset.page || '{}'); const settings = page.settings || {}; const nodes = { message: root.querySelector('[data-bind="message"]'), lastFetch: root.querySelector('[data-bind="last-fetch"]'), defaultBase: root.querySelector('[data-bind="default-base"]'), displayBase: root.querySelector('[data-bind="display-base"]'), ratesBody: root.querySelector('[data-bind="rates-body"]'), defaultBaseInput: root.querySelector('input[name="default_base_currency"]'), displayBaseInput: root.querySelector('input[name="display_base_currency"]'), preferredCurrenciesInput: root.querySelector('input[name="preferred_currencies"]'), }; const apiBase = '/api/fx-rates/v1'; const setMessage = (text, type = '') => { if (!nodes.message) { return; } nodes.message.textContent = text || ''; nodes.message.className = `fx-message${type ? ` is-${type}` : ''}`; }; const setLoading = (state) => { root.querySelectorAll('button[data-action]').forEach((button) => { button.disabled = state; }); }; const parsePreferredCurrencies = () => String(nodes.preferredCurrenciesInput?.value || '') .split(/[\s,;]+/) .map((item) => item.trim().toUpperCase()) .filter(Boolean); const renderSnapshot = (snapshot) => { const rates = snapshot && snapshot.rates ? snapshot.rates : null; const entries = rates ? Object.entries(rates) : []; if (!nodes.ratesBody) { return; } if (!entries.length) { nodes.ratesBody.innerHTML = 'Noch keine Wechselkurse fuer die ausgewaehlten Waehrungen gespeichert.'; return; } nodes.ratesBody.innerHTML = entries.map(([code, rate]) => { const formatted = typeof rate === 'number' ? rate.toLocaleString('de-DE', { maximumFractionDigits: 8 }) : 'n/a'; return `${code}${formatted}`; }).join(''); }; const request = async (path, options = {}) => { const response = await fetch(`${apiBase}${path}`, { credentials: 'same-origin', headers: { Accept: 'application/json', ...(options.body ? { 'Content-Type': 'application/json' } : {}), ...(options.headers || {}), }, ...options, }); const payload = await response.json().catch(() => ({})); if (!response.ok) { throw new Error(payload?.context?.message || payload?.error || `HTTP ${response.status}`); } return payload.data; }; const loadLatest = async () => { const base = String( nodes.displayBaseInput?.value || settings.display_base_currency || settings.default_base_currency || 'EUR' ).trim().toUpperCase(); const preferred = parsePreferredCurrencies(); const query = new URLSearchParams(); query.set('base', base); if (preferred.length) { query.set('symbols', preferred.join(',')); } const data = await request(`/latest?${query.toString()}`); renderSnapshot(data); if (nodes.lastFetch) { nodes.lastFetch.textContent = data?.fetched_at || 'noch keiner'; } if (nodes.displayBase) { nodes.displayBase.textContent = base; } return data; }; root.querySelector('[data-action="refresh-rates"]')?.addEventListener('click', async () => { try { setLoading(true); setMessage('Ich rufe jetzt die aktuellen Kurse ab.'); const payload = { force: true, base: String(nodes.defaultBaseInput?.value || settings.default_base_currency || 'EUR').trim().toUpperCase(), currencies: parsePreferredCurrencies(), }; const data = await request('/refresh', { method: 'POST', body: JSON.stringify(payload) }); setMessage(`Aktuelle Kurse gespeichert. ${data?.updated_count || 0} Werte aktualisiert.`, 'success'); await loadLatest(); } catch (error) { setMessage(error.message || 'Kurse konnten nicht aktualisiert werden.', 'error'); } finally { setLoading(false); } }); root.querySelector('[data-action="save-settings"]')?.addEventListener('click', async () => { try { setLoading(true); setMessage('Ich speichere jetzt die Waehrungs-Auswahl.'); const payload = { default_base_currency: String(nodes.defaultBaseInput?.value || '').trim().toUpperCase(), display_base_currency: String(nodes.displayBaseInput?.value || '').trim().toUpperCase(), preferred_currencies: parsePreferredCurrencies(), }; const data = await request('/settings', { method: 'PUT', body: JSON.stringify(payload) }); if (nodes.defaultBase) { nodes.defaultBase.textContent = data?.default_base_currency || ''; } if (nodes.displayBase) { nodes.displayBase.textContent = data?.display_base_currency || ''; } setMessage('Waehrungs-Auswahl gespeichert.', 'success'); await loadLatest(); } catch (error) { setMessage(error.message || 'Waehrungs-Auswahl konnte nicht gespeichert werden.', 'error'); } finally { setLoading(false); } }); loadLatest().catch((error) => { setMessage(error.message || 'Letzter Snapshot konnte nicht geladen werden.', 'error'); }); })();