MeshDD-Bot/static/js/login.js
ppfeiffer f2aa69333d feat: v0.7.1 - Hell-Theme als Standard
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 18:49:46 +01:00

174 lines
6.3 KiB
JavaScript

// Theme toggle
const themeToggle = document.getElementById('themeToggle');
const themeIcon = document.getElementById('themeIcon');
function applyTheme(theme) {
document.documentElement.setAttribute('data-bs-theme', theme);
themeIcon.className = theme === 'dark' ? 'bi bi-sun-fill' : 'bi bi-moon-fill';
localStorage.setItem('theme', theme);
}
applyTheme(localStorage.getItem('theme') || 'light');
themeToggle.addEventListener('click', () => {
const current = document.documentElement.getAttribute('data-bs-theme');
applyTheme(current === 'dark' ? 'light' : 'dark');
});
// Footer
(function () {
const footer = document.getElementById('pageFooter');
if (!footer) return;
const now = new Date();
const mm = String(now.getMonth() + 1).padStart(2, '0');
const yyyy = now.getFullYear();
fetch('/api/stats').then(r => r.ok ? r.json() : null).then(d => {
const ver = d?.version ? ` · v${d.version}` : '';
footer.textContent = `© MeshDD / PPfeiffer${ver} · ${mm}/${yyyy}`;
}).catch(() => {
footer.textContent = `© MeshDD / PPfeiffer · ${mm}/${yyyy}`;
});
})();
// View switching
const views = {
login: document.getElementById('loginView'),
register: document.getElementById('registerView'),
forgot: document.getElementById('forgotView'),
setPassword: document.getElementById('setPasswordView'),
};
function showView(name) {
Object.values(views).forEach(v => v.classList.add('d-none'));
views[name].classList.remove('d-none');
}
document.getElementById('showRegister').addEventListener('click', (e) => { e.preventDefault(); showView('register'); });
document.getElementById('showLoginFromReg').addEventListener('click', (e) => { e.preventDefault(); showView('login'); });
document.getElementById('showForgot').addEventListener('click', (e) => { e.preventDefault(); showView('forgot'); });
document.getElementById('showLoginFromForgot').addEventListener('click', (e) => { e.preventDefault(); showView('login'); });
// Check URL for token (verify or reset-password)
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token');
const isVerify = window.location.pathname === '/auth/verify';
const isReset = window.location.pathname === '/auth/reset-password';
if (token && (isVerify || isReset)) {
showView('setPassword');
document.getElementById('setPasswordTitle').textContent = isVerify ? 'Passwort setzen' : 'Passwort zuruecksetzen';
}
// Show register view if on /register
if (window.location.pathname === '/register') {
showView('register');
}
function showAlert(id, message, type) {
const el = document.getElementById(id);
el.className = `alert alert-${type} py-1 small`;
el.textContent = message;
}
// Login
document.getElementById('btnLogin').addEventListener('click', async () => {
const email = document.getElementById('loginEmail').value.trim();
const password = document.getElementById('loginPassword').value;
if (!email || !password) return;
try {
const resp = await fetch('/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
const data = await resp.json();
if (resp.ok) {
window.location.href = '/';
} else {
showAlert('loginAlert', data.error || 'Anmeldung fehlgeschlagen', 'danger');
}
} catch (e) {
showAlert('loginAlert', 'Verbindungsfehler', 'danger');
}
});
document.getElementById('loginPassword').addEventListener('keydown', (e) => {
if (e.key === 'Enter') document.getElementById('btnLogin').click();
});
// Register
document.getElementById('btnRegister').addEventListener('click', async () => {
const name = document.getElementById('registerName').value.trim();
const email = document.getElementById('registerEmail').value.trim();
if (!name || !email) return;
try {
const resp = await fetch('/auth/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, email })
});
const data = await resp.json();
if (resp.ok) {
showAlert('registerAlert', data.message || 'Registrierung erfolgreich', 'success');
} else {
showAlert('registerAlert', data.error || 'Registrierung fehlgeschlagen', 'danger');
}
} catch (e) {
showAlert('registerAlert', 'Verbindungsfehler', 'danger');
}
});
// Forgot password
document.getElementById('btnForgot').addEventListener('click', async () => {
const email = document.getElementById('forgotEmail').value.trim();
if (!email) return;
try {
const resp = await fetch('/auth/forgot-password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })
});
const data = await resp.json();
showAlert('forgotAlert', data.message || 'Link gesendet', 'success');
} catch (e) {
showAlert('forgotAlert', 'Verbindungsfehler', 'danger');
}
});
// Set password (verify + reset)
document.getElementById('btnSetPassword').addEventListener('click', async () => {
const password = document.getElementById('newPassword').value;
const confirm = document.getElementById('confirmPassword').value;
if (password.length < 8) {
showAlert('setPasswordAlert', 'Passwort muss mindestens 8 Zeichen lang sein', 'danger');
return;
}
if (password !== confirm) {
showAlert('setPasswordAlert', 'Passwoerter stimmen nicht ueberein', 'danger');
return;
}
const endpoint = isReset ? '/auth/reset-password' : '/auth/set-password';
try {
const resp = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token, password })
});
const data = await resp.json();
if (resp.ok) {
showAlert('setPasswordAlert', data.message || 'Passwort gespeichert', 'success');
setTimeout(() => { window.location.href = '/login'; }, 2000);
} else {
showAlert('setPasswordAlert', data.error || 'Fehler', 'danger');
}
} catch (e) {
showAlert('setPasswordAlert', 'Verbindungsfehler', 'danger');
}
});