Files
nat-as-server/website/js/pages/login.js

141 lines
5.9 KiB
JavaScript

import { navigate } from '../router.js';
import { isLoggedIn, showToast } from '../app.js';
export function loginPage() {
if (isLoggedIn()) { navigate('#/'); return; }
const app = document.getElementById('app');
app.innerHTML = `
<div class="login-wrapper">
<div class="login-card card">
<h1>BW Sch&uuml;tzt</h1>
<p class="subtitle">Questionnaire Management</p>
<form id="loginForm">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" autocomplete="username" required>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" autocomplete="current-password" required>
</div>
<button type="submit" class="btn btn-primary btn-block">Log in</button>
<p id="loginError" class="error-text" style="display:none"></p>
</form>
<div id="changePwSection" style="display:none">
<hr>
<p>You must change your password before continuing.</p>
<form id="changePwForm">
<div class="form-group">
<label for="newPw">New password</label>
<input type="password" id="newPw" autocomplete="new-password" required minlength="6">
</div>
<div class="form-group">
<label for="newPwConfirm">Confirm password</label>
<input type="password" id="newPwConfirm" autocomplete="new-password" required minlength="6">
</div>
<button type="submit" class="btn btn-primary btn-block">Change &amp; continue</button>
<p id="changePwError" class="error-text" style="display:none"></p>
</form>
</div>
</div>
</div>
`;
let pendingUsername = '';
let pendingTempToken = '';
document.getElementById('loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const errEl = document.getElementById('loginError');
errEl.style.display = 'none';
const username = document.getElementById('username').value.trim();
const password = document.getElementById('password').value;
try {
const res = await fetch('../api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-QDB-Client': 'web',
},
body: JSON.stringify({ username, password }),
});
const json = await res.json();
if (!json.ok) {
errEl.textContent = json.error?.message || 'Login failed';
errEl.style.display = '';
return;
}
const d = json.data;
if (d.role === 'coach') {
errEl.textContent = 'Coach accounts can only sign in through the mobile app.';
errEl.style.display = '';
return;
}
if (d.mustChangePassword) {
pendingUsername = username;
pendingTempToken = d.token;
document.getElementById('loginForm').style.display = 'none';
document.getElementById('changePwSection').style.display = '';
return;
}
localStorage.setItem('qdb_token', d.token);
localStorage.setItem('qdb_user', d.user);
localStorage.setItem('qdb_role', d.role);
navigate('#/');
} catch (err) {
errEl.textContent = err.message;
errEl.style.display = '';
}
});
document.getElementById('changePwForm').addEventListener('submit', async (e) => {
e.preventDefault();
const errEl = document.getElementById('changePwError');
errEl.style.display = 'none';
const newPw = document.getElementById('newPw').value;
const confirm = document.getElementById('newPwConfirm').value;
if (newPw !== confirm) {
errEl.textContent = 'Passwords do not match';
errEl.style.display = '';
return;
}
const oldPw = document.getElementById('password').value;
try {
const headers = {
'Content-Type': 'application/json',
'X-QDB-Client': 'web',
};
if (pendingTempToken) {
headers['Authorization'] = `Bearer ${pendingTempToken}`;
}
const res = await fetch('../api/auth/change-password', {
method: 'POST',
headers,
body: JSON.stringify({ username: pendingUsername, old_password: oldPw, new_password: newPw }),
});
const json = await res.json();
if (!json.ok) {
errEl.textContent = json.error?.message || 'Password change failed';
errEl.style.display = '';
return;
}
const d = json.data;
if (d.role === 'coach') {
errEl.textContent = 'Coach accounts can only sign in through the mobile app.';
errEl.style.display = '';
return;
}
localStorage.setItem('qdb_token', d.token);
localStorage.setItem('qdb_user', d.user);
localStorage.setItem('qdb_role', d.role);
showToast('Password changed successfully', 'success');
navigate('#/');
} catch (err) {
errEl.textContent = err.message;
errEl.style.display = '';
}
});
}