Dienstplan-Pro/auth-ui.js

112 lines
4.1 KiB
JavaScript

/**
* AuthUI — Login-Overlay, Admin-Nutzerverwaltung, Logout, Nutzer-Isolation.
* Hält app.js schlank; alle fetch mit credentials.
*/
const AuthUI = {
// Bei Nutzerwechsel/Logout zu leerende Schlüssel: Daten + pending + gerätelokaler OpenRouter-Key.
KEYS_TO_CLEAR: [
'dienstplan_employees', 'dienstplan_duties', 'dienstplan_vacation',
'dienstplan_sync_pending', 'dienstplan_openrouter_key', 'dienstplan_openrouter_model',
],
clearLocalData() { this.KEYS_TO_CLEAR.forEach(k => localStorage.removeItem(k)); },
showLogin() {
const ov = document.getElementById('login-overlay');
const cont = document.querySelector('.container');
if (ov) ov.hidden = false;
if (cont) cont.style.display = 'none';
this.wireLoginForm();
},
hideLogin() {
const ov = document.getElementById('login-overlay');
const cont = document.querySelector('.container');
if (ov) ov.hidden = true;
if (cont) cont.style.display = '';
},
wireLoginForm() {
const form = document.getElementById('login-form');
if (!form || form._wired) return;
form._wired = true;
form.addEventListener('submit', async (e) => {
e.preventDefault();
const email = (document.getElementById('login-email').value || '').trim();
try {
await fetch('/api/auth/request', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
credentials: 'include', body: JSON.stringify({ email }),
});
} catch { /* neutral bleiben */ }
const msg = document.getElementById('login-message');
if (msg) msg.hidden = false;
const btn = form.querySelector('button');
if (btn) btn.disabled = true;
});
},
showAdminSection() {
const sec = document.getElementById('admin-section');
if (sec) sec.hidden = false;
this.loadUsers();
const addForm = document.getElementById('admin-add-form');
if (addForm && !addForm._wired) {
addForm._wired = true;
addForm.addEventListener('submit', async (e) => {
e.preventDefault();
const input = document.getElementById('admin-add-email');
const email = (input.value || '').trim();
await fetch('/api/admin/users', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
credentials: 'include', body: JSON.stringify({ email }),
});
input.value = '';
this.loadUsers();
});
}
},
async loadUsers() {
const list = document.getElementById('admin-user-list');
if (!list) return;
try {
const res = await fetch('/api/admin/users', { credentials: 'include' });
if (!res.ok) return;
const { users } = await res.json();
list.innerHTML = '';
users.forEach((u) => {
const row = document.createElement('div');
row.className = 'admin-user-row';
row.style.cssText = 'display:flex;justify-content:space-between;align-items:center;padding:4px 0;border-bottom:1px solid #eee';
const span = document.createElement('span');
span.textContent = u.email + (u.isAdmin ? ' (Admin)' : '');
row.appendChild(span);
const btn = document.createElement('button');
btn.className = 'btn btn-secondary';
btn.textContent = 'Entfernen';
btn.addEventListener('click', async () => {
if (!confirm(`Nutzer ${u.email} entfernen?`)) return;
const r = await fetch('/api/admin/users/' + u.id, { method: 'DELETE', credentials: 'include' });
if (!r.ok) { const j = await r.json().catch(() => ({})); alert(j.error || 'Fehler beim Entfernen'); }
this.loadUsers();
});
row.appendChild(btn);
list.appendChild(row);
});
} catch { /* ignorieren */ }
},
wireLogout() {
const btn = document.getElementById('logout-btn');
if (!btn || btn._wired) return;
btn._wired = true;
btn.addEventListener('click', async () => {
try { await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' }); } catch { /* egal */ }
this.clearLocalData();
localStorage.removeItem('dienstplan_current_user');
location.reload();
});
},
};
if (typeof window !== 'undefined') window.AuthUI = AuthUI;