/** * Modul: Login-Seite * Zweck: Anmeldeformular mit Username/Passwort, Fehlerbehandlung, Session-Start * Abhängigkeiten: /api.js */ import { auth } from '/api.js'; import { t } from '/i18n.js'; const VERSION_URL = '/api/v1/version'; const DEFAULT_APP_NAME = 'Oikos'; const APP_NAME_STORAGE_KEY = 'oikos-app-name'; function getStoredAppName() { return localStorage.getItem(APP_NAME_STORAGE_KEY) || DEFAULT_APP_NAME; } function setAppBranding(appName) { const name = String(appName || '').trim() || DEFAULT_APP_NAME; document.title = name; const titleEl = document.querySelector('.login-hero__title'); if (titleEl) titleEl.textContent = name; } /** * Rendert die Login-Seite in den gegebenen Container. * @param {HTMLElement} container */ export async function render(container) { const storedAppName = getStoredAppName(); container.innerHTML = `

${storedAppName}

`; const form = container.querySelector('#login-form'); const errorEl = container.querySelector('#login-error'); const submitBtn = container.querySelector('#login-btn'); const versionEl = container.querySelector('#login-version'); setAppBranding(storedAppName); fetch(VERSION_URL, { cache: 'no-store' }) .then((r) => r.json()) .then((d) => { if (d?.app_name) { try { localStorage.setItem(APP_NAME_STORAGE_KEY, d.app_name); } catch (_) {} setAppBranding(d.app_name); } versionEl.textContent = t('login.version', { version: d.version }); }) .catch(() => {}); form.addEventListener('submit', async (e) => { e.preventDefault(); errorEl.hidden = true; const username = form.username.value.trim(); const password = form.password.value; if (!username || !password) { showError(errorEl, t('common.allFieldsRequired')); return; } submitBtn.disabled = true; submitBtn.textContent = t('login.loggingIn'); try { const result = await auth.login(username, password); window.oikos.navigate('/', result.user); } catch (err) { showError(errorEl, err.status === 429 ? t('login.tooManyAttempts') : t('login.invalidCredentials') ); } finally { submitBtn.disabled = false; submitBtn.textContent = t('login.loginButton'); } }); } function showError(el, message) { el.textContent = message; el.hidden = false; }