/
varsl
/
HTML-CSS
Обзор
Документация
Войти
/
varsl
/
HTML-CSS
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
frontend/js/auth.js
409 строк
16 KB
varsl
Добавление JavaScript логики
21 дек 2025, 23:16
21 дек 2025, 23:16
9dd2130
Код
Авторство
О чём код?
class AuthManager { constructor() { this.apiBaseUrl = 'http://localhost:3000/api'; this.currentUser = null; this.init(); } async init() { this.loadUserFromStorage(); this.setupEventListeners(); this.updateAuthUI(); } loadUserFromStorage() { const userData = localStorage.getItem('user'); const token = localStorage.getItem('token'); if (userData && token) { try { this.currentUser = JSON.parse(userData); } catch (error) { this.clearAuth(); console.error('Ошибка загрузки данных пользователя:', error); } } } clearAuth() { localStorage.removeItem('token'); localStorage.removeItem('user'); localStorage.removeItem('isLoggedIn'); this.currentUser = null; this.updateAuthUI(); } async login(email, password) { try { console.log('Отправка запроса на вход:', `${this.apiBaseUrl}/auth/login`); const response = await fetch(`${this.apiBaseUrl}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }); const data = await response.json(); console.log('Ответ от сервера:', data); if (!response.ok) { throw new Error(data.message || 'Ошибка авторизации'); } if (!data.success) { throw new Error(data.message || 'Ошибка авторизации'); } this.currentUser = data.user; localStorage.setItem('user', JSON.stringify(data.user)); localStorage.setItem('token', data.token); localStorage.setItem('isLoggedIn', 'true'); this.updateAuthUI(); return { success: true, user: data.user }; } catch (error) { console.error('Login error:', error); return { success: false, message: error.message }; } } async register(userData) { try { console.log('Регистрация пользователя:', userData); // Преобразуем данные в формат, который ожидает бэкенд const registrationData = { email: userData.email, password: userData.password, name: userData.firstName + ' ' + userData.lastName, phone: userData.phone || '', birthDate: userData.birthDate || null }; console.log('Отправка на сервер:', registrationData); const response = await fetch(`${this.apiBaseUrl}/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(registrationData) }); const data = await response.json(); console.log('Ответ сервера:', data); if (!response.ok) { throw new Error(data.message || 'Ошибка регистрации'); } if (!data.success) { throw new Error(data.message || 'Ошибка регистрации'); } return { success: true, user: data.user, message: data.message }; } catch (error) { console.error('Register error:', error); return { success: false, message: error.message }; } } async logout() { try { // Пытаемся отправить запрос на логаут на сервер const token = localStorage.getItem('token'); if (token) { await fetch(`${this.apiBaseUrl}/auth/logout`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }); } } catch (error) { console.error('Logout API error:', error); } finally { // Всегда очищаем локальные данные this.clearAuth(); window.location.href = 'index.html'; } } isAuthenticated() { return localStorage.getItem('isLoggedIn') === 'true' && localStorage.getItem('user') && localStorage.getItem('token'); } async getCurrentUser() { if (!this.isAuthenticated()) { return null; } try { const token = localStorage.getItem('token'); const response = await fetch(`${this.apiBaseUrl}/auth/me`, { headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { const data = await response.json(); if (data.success) { this.currentUser = data.user; localStorage.setItem('user', JSON.stringify(data.user)); return data.user; } } } catch (error) { console.error('Get user error:', error); } return null; } updateAuthUI() { const authButtons = document.querySelector('.auth-buttons'); if (!authButtons) return; if (this.isAuthenticated()) { const user = JSON.parse(localStorage.getItem('user') || '{}'); const userName = user.name || user.email || 'Пользователь'; authButtons.innerHTML = ` <div class="user-dropdown"> <button class="user-avatar-btn"> <i class="fas fa-user-circle"></i> ${userName} <i class="fas fa-chevron-down"></i> </button> <div class="dropdown-menu" style="display: none; position: absolute; background: white; border: 1px solid #ddd; border-radius: 5px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); min-width: 200px; z-index: 1000;"> <a href="profile.html" class="dropdown-item" style="display: block; padding: 10px 15px; color: #333; text-decoration: none; border-bottom: 1px solid #eee;"> <i class="fas fa-user"></i> Профиль </a> <a href="dashboard.html" class="dropdown-item" style="display: block; padding: 10px 15px; color: #333; text-decoration: none; border-bottom: 1px solid #eee;"> <i class="fas fa-chart-line"></i> Дашборд </a> <hr style="margin: 5px 0; border-color: #eee;"> <button class="dropdown-item logout-btn" style="display: block; width: 100%; text-align: left; padding: 10px 15px; background: none; border: none; color: #f44336; cursor: pointer;"> <i class="fas fa-sign-out-alt"></i> Выйти </button> </div> </div> `; const logoutBtn = authButtons.querySelector('.logout-btn'); const dropdownBtn = authButtons.querySelector('.user-avatar-btn'); const dropdownMenu = authButtons.querySelector('.dropdown-menu'); if (logoutBtn) { logoutBtn.addEventListener('click', () => this.logout()); } if (dropdownBtn && dropdownMenu) { dropdownBtn.addEventListener('click', (e) => { e.stopPropagation(); dropdownMenu.style.display = dropdownMenu.style.display === 'none' ? 'block' : 'none'; }); document.addEventListener('click', () => { dropdownMenu.style.display = 'none'; }); dropdownMenu.addEventListener('click', (e) => { e.stopPropagation(); }); } } else { authButtons.innerHTML = ` <a href="login.html" class="btn btn-outline"> <i class="fas fa-sign-in-alt"></i> Вход </a> <a href="register.html" class="btn btn-primary"> <i class="fas fa-user-plus"></i> Регистрация </a> `; } } setupEventListeners() { const loginForm = document.getElementById('loginForm'); const registerForm = document.getElementById('registerForm'); if (loginForm) { loginForm.addEventListener('submit', async (e) => { e.preventDefault(); const email = loginForm.querySelector('#email').value; const password = loginForm.querySelector('#password').value; const submitBtn = loginForm.querySelector('button[type="submit"]'); submitBtn.classList.add('btn-loading'); submitBtn.disabled = true; const result = await this.login(email, password); submitBtn.classList.remove('btn-loading'); submitBtn.disabled = false; if (result.success) { this.showNotification('Успешный вход!', 'success'); setTimeout(() => { window.location.href = 'profile.html'; }, 1000); } else { this.showNotification(result.message || 'Ошибка входа', 'error'); } }); } if (registerForm) { registerForm.addEventListener('submit', async (e) => { e.preventDefault(); // Сбор данных формы const formData = { firstName: registerForm.querySelector('#firstName').value.trim(), lastName: registerForm.querySelector('#lastName').value.trim(), email: registerForm.querySelector('#email').value.trim(), phone: registerForm.querySelector('#phone').value.trim(), birthDate: registerForm.querySelector('#birthDate').value, password: registerForm.querySelector('#password').value, confirmPassword: registerForm.querySelector('#confirmPassword').value, newsletter: registerForm.querySelector('#newsletterSubscribe')?.checked || false }; // Валидация if (formData.password !== formData.confirmPassword) { this.showNotification('Пароли не совпадают', 'error'); return; } if (formData.password.length < 6) { this.showNotification('Пароль должен содержать минимум 6 символов', 'error'); return; } const submitBtn = registerForm.querySelector('button[type="submit"]'); submitBtn.classList.add('btn-loading'); submitBtn.disabled = true; const result = await this.register(formData); submitBtn.classList.remove('btn-loading'); submitBtn.disabled = false; if (result.success) { this.showNotification(result.message || 'Регистрация успешна! Теперь войдите в систему.', 'success'); setTimeout(() => { window.location.href = 'login.html'; }, 2000); } else { this.showNotification(result.message || 'Ошибка регистрации', 'error'); } }); } } showNotification(message, type = 'info') { // Удаляем старые уведомления const oldNotifications = document.querySelectorAll('.notification'); oldNotifications.forEach(n => n.remove()); const notification = document.createElement('div'); notification.className = `notification notification-${type}`; notification.style.cssText = ` position: fixed; top: 20px; right: 20px; padding: 1rem 1.5rem; border-radius: 8px; background: white; box-shadow: 0 4px 12px rgba(0,0,0,0.15); transform: translateX(100%); opacity: 0; transition: all 0.3s ease; z-index: 1000; max-width: 350px; border-left: 4px solid ${type === 'success' ? '#2E7D32' : type === 'error' ? '#f44336' : '#2196F3'}; `; notification.innerHTML = ` <div class="notification-content" style="display: flex; align-items: center; gap: 0.75rem;"> <i class="fas fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : 'info-circle'}" style="color: ${type === 'success' ? '#2E7D32' : type === 'error' ? '#f44336' : '#2196F3'}"></i> <span style="flex: 1;">${message}</span> </div> <button class="notification-close" style="position: absolute; top: 10px; right: 10px; background: none; border: none; color: #999; cursor: pointer; font-size: 0.875rem;"> <i class="fas fa-times"></i> </button> `; document.body.appendChild(notification); // Показываем с анимацией setTimeout(() => { notification.style.transform = 'translateX(0)'; notification.style.opacity = '1'; }, 10); // Закрытие по клику const closeBtn = notification.querySelector('.notification-close'); closeBtn.addEventListener('click', () => { notification.style.transform = 'translateX(100%)'; notification.style.opacity = '0'; setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 300); }); // Автоматическое скрытие setTimeout(() => { if (notification.parentNode) { notification.style.transform = 'translateX(100%)'; notification.style.opacity = '0'; setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 300); } }, 5000); } } // Создаем глобальный экземпляр AuthManager window.authManager = new AuthManager(); // Проверка авторизации при загрузке страницы document.addEventListener('DOMContentLoaded', function() { const protectedRoutes = ['profile.html', 'dashboard.html']; const currentPage = window.location.pathname.split('/').pop(); // Если пользователь не авторизован и пытается зайти на защищенную страницу if (protectedRoutes.includes(currentPage) && !authManager.isAuthenticated()) { window.location.href = 'login.html'; return; } // Если пользователь авторизован и пытается зайти на страницу входа/регистрации if ((currentPage === 'login.html' || currentPage === 'register.html') && authManager.isAuthenticated()) { window.location.href = 'profile.html'; return; } // Обновляем UI авторизации на всех страницах authManager.updateAuthUI(); });