feat: backend auth, admin panel, role-based routing
This commit is contained in:
106
frontend/script.js
Normal file
106
frontend/script.js
Normal file
@@ -0,0 +1,106 @@
|
||||
(() => {
|
||||
'use strict';
|
||||
|
||||
const form = document.getElementById('login-form');
|
||||
const usernameInput = document.getElementById('username');
|
||||
const passwordInput = document.getElementById('password');
|
||||
const usernameError = document.getElementById('username-error');
|
||||
const passwordError = document.getElementById('password-error');
|
||||
const formAlert = document.getElementById('form-alert');
|
||||
const btnSubmit = document.getElementById('btn-submit');
|
||||
const btnText = btnSubmit.querySelector('.btn-text');
|
||||
const btnLoader = btnSubmit.querySelector('.btn-loader');
|
||||
const togglePassword = document.getElementById('toggle-password');
|
||||
|
||||
togglePassword.addEventListener('click', () => {
|
||||
const isPassword = passwordInput.type === 'password';
|
||||
passwordInput.type = isPassword ? 'text' : 'password';
|
||||
togglePassword.setAttribute('aria-label', isPassword ? 'Скрыть пароль' : 'Показать пароль');
|
||||
});
|
||||
|
||||
usernameInput.addEventListener('input', () => clearFieldError(usernameInput, usernameError));
|
||||
passwordInput.addEventListener('input', () => clearFieldError(passwordInput, passwordError));
|
||||
|
||||
function clearFieldError(input, errorEl) {
|
||||
input.closest('.form-group').classList.remove('has-error');
|
||||
errorEl.textContent = '';
|
||||
}
|
||||
|
||||
function setFieldError(input, errorEl, message) {
|
||||
input.closest('.form-group').classList.add('has-error');
|
||||
errorEl.textContent = message;
|
||||
}
|
||||
|
||||
function showAlert(message, type) {
|
||||
formAlert.className = 'form-alert ' + type;
|
||||
formAlert.textContent = message;
|
||||
}
|
||||
|
||||
function hideAlert() {
|
||||
formAlert.className = 'form-alert';
|
||||
formAlert.textContent = '';
|
||||
}
|
||||
|
||||
function setLoading(loading) {
|
||||
btnSubmit.disabled = loading;
|
||||
btnText.hidden = loading;
|
||||
btnLoader.hidden = !loading;
|
||||
}
|
||||
|
||||
function validate() {
|
||||
let valid = true;
|
||||
hideAlert();
|
||||
|
||||
if (!usernameInput.value.trim()) {
|
||||
setFieldError(usernameInput, usernameError, 'Введите имя пользователя');
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!passwordInput.value) {
|
||||
setFieldError(passwordInput, passwordError, 'Введите пароль');
|
||||
valid = false;
|
||||
} else if (passwordInput.value.length < 4) {
|
||||
setFieldError(passwordInput, passwordError, 'Минимум 4 символа');
|
||||
valid = false;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
if (!validate()) return;
|
||||
|
||||
setLoading(true);
|
||||
hideAlert();
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
username: usernameInput.value.trim(),
|
||||
password: passwordInput.value,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
showAlert('Вход выполнен успешно!', 'success');
|
||||
|
||||
if (data.token) localStorage.setItem('token', data.token);
|
||||
if (data.role) localStorage.setItem('role', data.role);
|
||||
|
||||
const redirect = data.redirect || '/';
|
||||
setTimeout(() => { window.location.href = redirect; }, 400);
|
||||
} else {
|
||||
showAlert(data.message || 'Неверное имя пользователя или пароль', 'error');
|
||||
}
|
||||
} catch (err) {
|
||||
showAlert('Ошибка соединения с сервером', 'error');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user