Создана система регистрации пользователя
This commit is contained in:
parent
13754eecc3
commit
229826acc3
10 changed files with 1332 additions and 40 deletions
|
|
@ -172,7 +172,7 @@ import { SITE_URL } from '@constants';
|
|||
<div class="modal-content">
|
||||
<h2 class="modal-title">Политика обработки персональных данных</h2>
|
||||
<div class="privacy-text">
|
||||
<p>Настоящая политика обработки персональных данных (далее — Политика) определяет порядок обработки персональных данных пользователей сайта avtourist.ru.</p>
|
||||
<p>Настоящая политика обработки персональных данных (далее — Политика) определяет порядок обработки персональных данных пользователей сайта avtourist-surgut.ru.</p>
|
||||
|
||||
<h3>1. Общие положения</h3>
|
||||
<p>1.1. Обработка персональных данных осуществляется на основе принципов законности, справедливости и конфиденциальности.</p>
|
||||
|
|
@ -533,6 +533,73 @@ import { SITE_URL } from '@constants';
|
|||
box-shadow: 0 4px 12px rgba(206, 159, 64, 0.4);
|
||||
}
|
||||
|
||||
/* Success message */
|
||||
.success-message {
|
||||
text-align: center;
|
||||
padding: 2rem 1rem;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
||||
border-radius: 50%;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.success-icon svg {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.success-message h3 {
|
||||
color: #1e3050;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
.success-message p {
|
||||
color: #64748b;
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
margin: 0 0 0.75rem;
|
||||
}
|
||||
|
||||
.success-message .hint {
|
||||
color: #94a3b8;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.success-message + .auth-footer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.success-message .btn-submit {
|
||||
display: block;
|
||||
margin-top: 1.5rem;
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
background: linear-gradient(135deg, #eac26e 0%, #ce9f40 100%);
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 0.75rem;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.success-message .btn-submit:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 20px rgba(206, 159, 64, 0.4);
|
||||
}
|
||||
|
||||
/* Кнопка отправки */
|
||||
.btn-submit {
|
||||
background: linear-gradient(135deg, #eac26e 0%, #ce9f40 100%);
|
||||
|
|
@ -552,6 +619,12 @@ import { SITE_URL } from '@constants';
|
|||
box-shadow: 0 8px 20px rgba(206, 159, 64, 0.4);
|
||||
}
|
||||
|
||||
.btn-submit:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.btn-submit:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
|
@ -623,13 +696,11 @@ import { SITE_URL } from '@constants';
|
|||
}
|
||||
|
||||
function validateFirstName(value: string): boolean {
|
||||
const regex = /^[а-яА-ЯёЁ\-]+$/;
|
||||
return regex.test(value);
|
||||
return /^[а-яА-ЯёЁ\-]+$/.test(value);
|
||||
}
|
||||
|
||||
function validateLastName(value: string): boolean {
|
||||
const regex = /^[а-яА-ЯёЁ\-]+$/;
|
||||
return regex.test(value);
|
||||
return /^[а-яА-ЯёЁ\-]+$/.test(value);
|
||||
}
|
||||
|
||||
function validateEmail(value: string): boolean {
|
||||
|
|
@ -650,6 +721,7 @@ import { SITE_URL } from '@constants';
|
|||
document.querySelectorAll('.toggle-password').forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const targetId = button.getAttribute('data-target');
|
||||
if (!targetId) return;
|
||||
const input = document.getElementById(targetId) as HTMLInputElement;
|
||||
if (input) {
|
||||
const isPassword = input.type === 'password';
|
||||
|
|
@ -660,9 +732,10 @@ import { SITE_URL } from '@constants';
|
|||
});
|
||||
|
||||
firstNameInput?.addEventListener('input', () => {
|
||||
const value = firstNameInput.value.replace(/[^а-яА-ЯёЁ\-]/g, '');
|
||||
const value = firstNameInput.value.replace(/[^\w\u0400-\u04FF\-]/gi, '');
|
||||
firstNameInput.value = value;
|
||||
if (firstNameInput.value && !validateFirstName(firstNameInput.value)) {
|
||||
const trimmed = value ? value.trim() : '';
|
||||
if (trimmed.length > 0 && !validateFirstName(trimmed)) {
|
||||
showError(firstNameInput, 'Используйте только русские буквы');
|
||||
} else {
|
||||
clearError(firstNameInput);
|
||||
|
|
@ -670,9 +743,10 @@ import { SITE_URL } from '@constants';
|
|||
});
|
||||
|
||||
lastNameInput?.addEventListener('input', () => {
|
||||
const value = lastNameInput.value.replace(/[^а-яА-ЯёЁ\-]/g, '');
|
||||
const value = lastNameInput.value.replace(/[^\w\u0400-\u04FF\-]/gi, '');
|
||||
lastNameInput.value = value;
|
||||
if (lastNameInput.value && !validateLastName(lastNameInput.value)) {
|
||||
const trimmed = value ? value.trim() : '';
|
||||
if (trimmed.length > 0 && !validateLastName(trimmed)) {
|
||||
showError(lastNameInput, 'Используйте только русские буквы');
|
||||
} else {
|
||||
clearError(lastNameInput);
|
||||
|
|
@ -751,21 +825,27 @@ import { SITE_URL } from '@constants';
|
|||
return;
|
||||
}
|
||||
|
||||
const name = formData.get('firstName') as string;
|
||||
const firstName = formData.get('firstName') as string;
|
||||
const lastName = formData.get('lastName') as string;
|
||||
const email = formData.get('email') as string;
|
||||
const email = (formData.get('email') as string) || '';
|
||||
const phone = formData.get('phone') as string;
|
||||
const password = formData.get('password') as string;
|
||||
const confirmPassword = formData.get('confirmPassword') as string;
|
||||
|
||||
let hasErrors = false;
|
||||
|
||||
if (!validateFirstName(firstName)) {
|
||||
if (!firstName || typeof firstName !== 'string' || !firstName.trim()) {
|
||||
showError(firstNameInput, 'Введите имя');
|
||||
hasErrors = true;
|
||||
} else if (!validateFirstName(firstName)) {
|
||||
showError(firstNameInput, 'Введите имя (только русские буквы)');
|
||||
hasErrors = true;
|
||||
}
|
||||
|
||||
if (!validateLastName(lastName)) {
|
||||
if (!lastName || typeof lastName !== 'string' || !lastName.trim()) {
|
||||
showError(lastNameInput, 'Введите фамилию');
|
||||
hasErrors = true;
|
||||
} else if (!validateLastName(lastName)) {
|
||||
showError(lastNameInput, 'Введите фамилию (только русские буквы)');
|
||||
hasErrors = true;
|
||||
}
|
||||
|
|
@ -794,7 +874,53 @@ import { SITE_URL } from '@constants';
|
|||
return;
|
||||
}
|
||||
|
||||
console.log('Регистрация:', { firstName, lastName, email, phone, password });
|
||||
// Отправка данных на сервер
|
||||
const submitBtn = form.querySelector('.btn-submit') as HTMLButtonElement;
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = 'Регистрация...';
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/auth/sign-up', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ firstName, lastName, email, phone, password }),
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
// Показываем success message и скрываем footer
|
||||
form.innerHTML = `
|
||||
<div class="success-message" style="text-align: center; padding: 1rem 0;">
|
||||
<div class="success-icon" style="width: 80px; height: 80px; background: linear-gradient(135deg, #10b981 0%, #059669 100%); border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 1.5rem;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
||||
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 style="color: #1e3050; font-size: 1.5rem; font-weight: 700; margin: 0 0 1rem;">Регистрация успешна!</h3>
|
||||
<p style="color: #64748b; font-size: 1rem; line-height: 1.6; margin: 0 0 0.75rem;">На ваш email <strong>${email || ''}</strong> отправлена ссылка для подтверждения регистрации.</p>
|
||||
<p style="color: #94a3b8; font-size: 0.875rem;">Проверьте почту и перейдите по ссылке для активации аккаунта.</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Скрываем footer с ссылкой на вход
|
||||
const authFooter = document.querySelector('.auth-footer') as HTMLElement;
|
||||
if (authFooter) {
|
||||
authFooter.style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
showError(emailInput, result.error || 'Ошибка регистрации');
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Зарегистрироваться';
|
||||
}
|
||||
} catch (err) {
|
||||
showError(emailInput, 'Ошибка соединения');
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Зарегистрироваться';
|
||||
}
|
||||
});
|
||||
|
||||
// Модальное окно политики
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue