diff --git a/API/utils.py b/API/utils.py index 5e5c295..f046c77 100644 --- a/API/utils.py +++ b/API/utils.py @@ -62,4 +62,5 @@ class DataBase : if data["id"] == {} : return {"code": 1} else : - return {"code": 0, "data": {"id": data["id"]["0"], "email": email, "urls": data["urls"]["0"], "payment": data["payment"]["0"]}} \ No newline at end of file + return {"code": 0, "data": {"id": data["id"]["0"], "email": email, "urls": data["urls"]["0"], "payment": data["payment"]["0"]}} + diff --git a/Frontend/JS/register.js b/Frontend/JS/register.js index e69de29..a2757f9 100644 --- a/Frontend/JS/register.js +++ b/Frontend/JS/register.js @@ -0,0 +1,137 @@ +const API_URL = "https://spectralvpn.ru:{port}"; + +async function sha256(text) { + const encoder = new TextEncoder(); + const data = encoder.encode(text); + const hash = await crypto.subtle.digest('SHA-256', data); + return Array.from(new Uint8Array(hash)) + .map(b => b.toString(16).padStart(2, '0')) + .join(''); +} + +function clearErrors() { + document.querySelectorAll('.error').forEach(el => { + el.textContent = ''; + el.classList.remove('active'); + }); + document.querySelectorAll('.input, .checkbox').forEach(el => { + el.classList.remove('invalid'); + }); +} + +function showError(fieldId, message) { + const errorEl = document.getElementById(fieldId); + errorEl.textContent = message; + errorEl.classList.add('active'); + + const input = document.getElementById(fieldId.replace('Error', '')); + if (input) input.classList.add('invalid'); +} + +async function registration(e) { + e.preventDefault(); + clearErrors(); + + const email = document.getElementById("email").value.trim(); + const password = document.getElementById("password").value; + const passwordReply = document.getElementById("password_reply").value; + const terms = document.getElementById("terms").checked; + + let hasError = false; + + if (!email) { + showError("emailError", "Введите email"); + hasError = true; + } else if (!/^\S+@\S+\.\S+$/.test(email)) { + showError("emailError", "Некорректный email"); + hasError = true; + } + + if (!password) { + showError("passwordError", "Введите пароль"); + hasError = true; + } else if (password.length < 6) { + showError("passwordError", "Пароль должен быть не менее 6 символов"); + hasError = true; + } + + if (password !== passwordReply) { + showError("passwordReplyError", "Пароли не совпадают"); + hasError = true; + } + + if (!terms) { + showError("termsError", "Необходимо принять пользовательское соглашение"); + document.getElementById("terms").classList.add('invalid'); + hasError = true; + } + + if (hasError) return; + + const submitBtn = e.target.querySelector("button[type='submit']"); + const originalText = submitBtn.textContent; + submitBtn.disabled = true; + submitBtn.textContent = "Создаём аккаунт..."; + + try { + const hashedPassword = await sha256(password); + + const response = await fetch(`${API_URL}/registration`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + email: email, + password: hashedPassword + }) + }); + + const data = await response.json(); + + if (response.ok) { + alert("Аккаунт успешно создан! Перенаправляем в личный кабинет..."); + localStorage.setItem("user", JSON.stringify({ + id: data.id, + email: data.email, + loggedIn: true, + loginTime: Date.now() + })); + + window.location.href = "control-panel.html"; + + } else { + if (data.detail === "Email is busy.") { + showError("emailError", "Этот email уже зарегистрирован"); + } else { + alert("Ошибка регистрации: " + (data.detail || "Попробуйте позже")); + } + } + } catch (err) { + console.error("Registration error:", err); + alert("Нет соединения с сервером. Проверьте интернет или попробуйте позже."); + } finally { + submitBtn.disabled = false; + submitBtn.textContent = originalText; + } +} + +document.addEventListener("DOMContentLoaded", () => { + const form = document.getElementById("registerForm"); + if (form) { + form.addEventListener("submit", registration); + } + + // Подсветка полей при фокусе + document.querySelectorAll('.input').forEach(input => { + input.addEventListener('focus', () => { + input.classList.remove('invalid'); + const errorId = input.id + "Error"; + const errorEl = document.getElementById(errorId); + if (errorEl) { + errorEl.textContent = ''; + errorEl.classList.remove('active'); + } + }); + }); +}); \ No newline at end of file diff --git a/Frontend/Pages/register.html b/Frontend/Pages/register.html index 463f566..3ca3331 100644 --- a/Frontend/Pages/register.html +++ b/Frontend/Pages/register.html @@ -6,6 +6,7 @@ Регистрация - SpectralVPN +
@@ -14,22 +15,18 @@
- +
- +
-
- - -

Уже есть аккаунт? Войти

- \ No newline at end of file + diff --git a/Frontend/Styles/register.css b/Frontend/Styles/register.css index 630c245..6f95f92 100644 --- a/Frontend/Styles/register.css +++ b/Frontend/Styles/register.css @@ -125,9 +125,27 @@ p{ font-size: 0.85rem; margin-top: 6px; min-height: 20px; + opacity: 0; + transition: opacity 0.2s ease; } -@media (max-width: 480px) { +.error.active{ + opacity: 1; +} + +.input.invalid, +.checkbox.invalid{ + border-color: #ff6b6b !important; + box-shadow: 0 0 8px rgba(255, 107, 107, 0.3); +} + +button:disabled{ + opacity: 0.7; + cursor: not-allowed; + transform: none !important; +} + +@media (max-width: 480px){ form{ padding: 25px 20px; }