feat: complete Epic 1 production foundation

This commit is contained in:
2026-08-25 01:24:11 +03:00
parent 767428436d
commit 182bde8ac0
298 changed files with 35719 additions and 5299 deletions
+73 -5
View File
@@ -3,6 +3,17 @@
return window.t ? t(key) : key;
}
function diagnosticSuffix(error) {
var parts = [];
if (error && error.requestId) {
parts.push(tKey('login.error.request_id') + ': ' + error.requestId);
}
if (error && error.traceId) {
parts.push(tKey('login.error.trace_id') + ': ' + error.traceId);
}
return parts.length ? ('\n' + parts.join('\n')) : '';
}
function showError(message) {
var errorElement = document.getElementById('login-error');
errorElement.classList.add('is-visible');
@@ -14,34 +25,91 @@
errorElement.classList.remove('is-visible');
}
function setBootstrapMode(enabled) {
var emailField = document.getElementById('login-email-field');
var tokenField = document.getElementById('login-bootstrap-token-field');
var heading = document.querySelector('.login-heading');
var subtitle = document.querySelector('.login-sub');
var note = document.querySelector('.login-note');
var submit = document.getElementById('login-submit');
var password = document.getElementById('password');
document.getElementById('login-form').dataset.bootstrap = enabled ? 'true' : 'false';
if (emailField) emailField.hidden = enabled;
if (tokenField) tokenField.hidden = !enabled;
if (heading) heading.textContent = tKey(enabled ? 'login.bootstrap.title' : 'login.title');
if (subtitle) subtitle.textContent = tKey(enabled ? 'login.bootstrap.subtitle' : 'login.subtitle');
if (note) note.textContent = tKey(enabled ? 'login.bootstrap.note' : 'login.password_only');
if (submit) submit.textContent = tKey(enabled ? 'login.bootstrap.submit' : 'login.submit');
if (password) password.setAttribute('autocomplete', enabled ? 'new-password' : 'current-password');
}
function initLoginPage() {
var inFlight = false;
window.CrankAuth.guardLoginPage().catch(function(error) {
if (window.CrankDiagnostics && typeof window.CrankDiagnostics.report === 'function') {
window.CrankDiagnostics.report('guard-login-page', error, 'login');
}
});
setBootstrapMode(false);
window.CrankApi.getBootstrapStatus()
.then(function(status) {
setBootstrapMode(Boolean(status && status.bootstrap_required));
})
.catch(function(error) {
if (window.CrankDiagnostics && typeof window.CrankDiagnostics.report === 'function') {
window.CrankDiagnostics.report('bootstrap-status', error, 'login');
}
});
document.getElementById('login-form').addEventListener('submit', async function(event) {
event.preventDefault();
if (inFlight) {
return;
}
var form = event.currentTarget;
var isBootstrap = event.currentTarget.dataset.bootstrap === 'true';
var email = document.getElementById('email').value.trim();
var token = document.getElementById('bootstrap-token').value.trim();
var password = document.getElementById('password').value;
var submit = document.getElementById('login-submit');
if (!email || !password) {
showError(tKey('login.error.required'));
if ((!isBootstrap && !email) || (isBootstrap && !token) || !password) {
showError(tKey(isBootstrap ? 'login.bootstrap.error.required' : 'login.error.required'));
return;
}
hideError();
inFlight = true;
if (submit) {
submit.disabled = true;
submit.textContent = tKey(isBootstrap ? 'login.bootstrap.loading' : 'login.loading');
}
try {
await window.CrankAuth.login(email, password);
if (isBootstrap) {
await window.CrankAuth.completeBootstrap(token, password);
} else {
await window.CrankAuth.login(email, password);
}
showError(tKey(isBootstrap ? 'login.bootstrap.success' : 'login.success'));
} catch (error) {
if (error && error.status === 401) {
showError(tKey('login.error.invalid'));
showError(tKey('login.error.invalid') + diagnosticSuffix(error));
return;
}
showError(tKey('login.error.generic'));
if (error && error.status === 429) {
showError(tKey('login.error.throttled') + diagnosticSuffix(error));
return;
}
showError(tKey('login.error.generic') + diagnosticSuffix(error));
} finally {
inFlight = false;
if (submit && form.isConnected) {
submit.disabled = false;
submit.textContent = tKey(isBootstrap ? 'login.bootstrap.submit' : 'login.submit');
}
}
});
}