This commit is contained in:
Evdokia
2025-05-07 14:50:35 +03:00
parent fbff8f9c9c
commit 615fcc9246
4 changed files with 227 additions and 172 deletions

View File

@@ -1,64 +1,63 @@
.auth-page {
display: flex;
justify-content: center;
align-items: center;
min-height: calc(100vh - 160px);
padding: 40px 0;
}
display: flex;
justify-content: center;
align-items: center;
min-height: calc(100vh - 160px);
padding: 40px 0;
}
.auth-container {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
width: 400px;
max-width: 90%;
}
.auth-container {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
width: 400px;
max-width: 90%;
}
.auth-container h2 {
margin-top: 0;
color: #2c3e50;
text-align: center;
}
.auth-container h2 {
margin-top: 0;
color: #2c3e50;
text-align: center;
}
.form-group {
margin-bottom: 20px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
.form-group input {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 16px;
}
.form-group input {
width: 100%;
padding: 5px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 16px;
}
.auth-btn {
width: 100%;
padding: 14px;
background: #6C63FF;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin-top: 20px;
}
.auth-btn {
width: 100%;
padding: 14px;
background: #6C63FF;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin-top: 20px;
}
.auth-switch {
margin-top: 25px;
text-align: center;
color: #7f8c8d;
}
.auth-switch a {
color: #6C63FF;
text-decoration: none;
}
.auth-switch {
margin-top: 25px;
text-align: center;
color: #7f8c8d;
}
.auth-switch a {
color: #6C63FF;
text-decoration: none;
}

View File

@@ -1,78 +1,85 @@
import React, { useState } from 'react'; // Хук состояния
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { mockFetch } from './mockFetch';
import './AuthForms.css';
function Login() {
// Состояние для хранения данных формы
const [formData, setFormData] = useState({
email: '',
password: ''
});
// Хук для программной навигации
export default function Login() {
const [formData, setFormData] = useState({ login: '', password: '' }); // Состояние для хранения данных формы
const [error, setError] = useState(null);// для хранения сообщения об ошибке
const navigate = useNavigate();
// Обработчик изменений в полях ввода
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev, // Сохранение предыдущих значений
[name]: value // Динамическое обновление поля
}));
// Функция, которая вызывается при изменении любого поля формы, обновляет соответствующее поле в formData и сбрасывает ошибку
const handleChange = e => {
setFormData(prev => ({ ...prev, [e.target.name]: e.target.value }));
setError(null);
};
// Обработчик отправки формы
const handleSubmit = (e) => {
e.preventDefault(); // Отмена стандартного поведения
console.log('Вход:', formData); // Логирование данных (в реальном приложении - запрос к API)
navigate('/'); // Перенаправление на главную страницу
// Функция, которая вызывается при отправке формы
const handleSubmit = async e => {
e.preventDefault(); // Отменяем стандартное поведение формы (перезагрузку страницы)
// Отправляем данные формы через mockFetch на "адрес" /api/login методом POST
const response = await mockFetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }, // Указываем, что отправляем JSON
body: JSON.stringify(formData), // Преобразуем объект с логином и паролем в JSON-строку
});
const data = await response.json(); // Получаем ответ в формате JSON
if (response.ok) {
// Если ответ успешный, сохраняем токен в localStorage
localStorage.setItem('token', data.token);
alert('Вход успешен!');
navigate('/');
} else {
setError(data.message);
}
};
return (
// Основной контейнер страницы
<div className="auth-page">
<div className="auth-container">
<h2>Вход</h2>
{error && <p style={{ color: 'red', textAlign: 'center' }}>{error}</p>}
{/* Форма с обработчиком отправки */}
<form onSubmit={handleSubmit}>
{/* Группа полей для email */}
{/* Поле для ввода логина */}
<div className="form-group">
<label>Email</label>
<label htmlFor="login">Логин</label>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
required // Обязательное поле
id="login"
name="login"
type="text"
value={formData.login} // Значение из состояния
onChange={handleChange} // Обновляем состояние при изменении
required // Поле обязательно для заполнения
/>
</div>
{/* Группа полей для пароля */}
<div className="form-group">
<label>Пароль</label>
<label htmlFor="password">Пароль</label>
<input
type="password"
id="password"
name="password"
type="password"
value={formData.password}
onChange={handleChange}
required
/>
</div>
{/* Кнопка отправки формы */}
<button type="submit" className="auth-btn">
Войти
</button>
<button type="submit" className="auth-btn">Войти</button>
</form>
{/* Ссылка для перехода к регистрации */}
<div className="auth-switch">
<span>Нет аккаунта? <a href="/register">Создать</a></span>
Нет аккаунта? <a href="/register">Зарегистрироваться</a>
</div>
</div>
</div>
);
}
export default Login;

View File

@@ -1,36 +1,41 @@
import React, { useState } from 'react'; //для управления состоянием формы
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { mockFetch } from './mockFetch';
import './AuthForms.css';
function Register() {
// Состояние для хранения данных формы
const [formData, setFormData] = useState({
name: '',
email: '',
password: ''
});
export default function Register() {
// Состояние для хранения данных формы: логин, email и пароль
const [formData, setFormData] = useState({ login: '', email: '', password: '' });
const [error, setError] = useState(null);
const navigate = useNavigate(); //для программного перехода на другую страницу
// Хук для навигации между страницами
const navigate = useNavigate();
// Обработчик изменений в полях ввода
const handleChange = (e) => {
const { name, value } = e.target; // Извлекаем имя поля и значение
setFormData(prev => ({
...prev, // Копируем предыдущее состояние
[name]: value // Обновляем конкретное поле
}));
// Функция вызывается при изменении любого поля формы, обновляет соответствующее поле в formData и сбрасывает ошибку
const handleChange = e => {
setFormData(prev => ({ ...prev, [e.target.name]: e.target.value }));
setError(null);
};
// Обработчик отправки формы
const handleSubmit = (e) => {
e.preventDefault(); // Отменяем стандартное поведение формы
// Функция вызывается при отправке формы
const handleSubmit = async e => {
e.preventDefault(); // Отменяем перезагрузку страницы
// В реальном приложении здесь будет запрос к API
console.log('Регистрация:', formData);
// Отправляем данные формы через mockFetch на "адрес" /api/register методом POST
const response = await mockFetch('/api/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }, // Заголовок, что данные в формате JSON
body: JSON.stringify(formData), // Преобразуем объект formData в JSON-строку
});
// Перенаправляем на главную страницу
navigate('/');
const data = await response.json(); // для программного перехода на другую страницу
if (response.ok) {
// Если регистрация успешна, показываем сообщение и переходим на страницу входа
alert(data.message);
navigate('/login');
} else {
// Если произошла ошибка, сохраняем её в состоянии для отображения
setError(data.message);
}
};
return (
@@ -38,56 +43,54 @@ function Register() {
<div className="auth-container">
<h2>Регистрация</h2>
<form onSubmit={handleSubmit}> {/* Форма с обработчиком отправки */}
{/* Группа полей для имени */}
{error && <p style={{ color: 'red', textAlign: 'center' }}>{error}</p>}
{/* Форма с обработчиком отправки */}
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>Имя</label>
<label htmlFor="login">Логин</label>
<input
id="login"
name="login"
type="text"
name="name"
value={formData.name} // Привязка к состоянию
onChange={handleChange} // Обработчик изменений
required // Обязательное поле
value={formData.login} // Значение из состояния
onChange={handleChange} // Обработчик изменения
required // Поле обязательно для заполнения
/>
</div>
{/* Группа полей для email */}
<div className="form-group">
<label>Email</label>
<label htmlFor="email">Email</label>
<input
type="email"
id="email"
name="email"
type="email"
value={formData.email}
onChange={handleChange}
required
/>
</div>
{/* Группа полей для пароля */}
<div className="form-group">
<label>Пароль</label>
<label htmlFor="password">Пароль</label>
<input
type="password"
id="password"
name="password"
type="password"
value={formData.password}
onChange={handleChange}
required
/>
</div>
{/* Кнопка отправки формы */}
<button type="submit" className="auth-btn">
Зарегистрироваться
</button>
<button type="submit" className="auth-btn">Зарегистрироваться</button>
</form>
{/* Ссылка для перехода к авторизации */}
<div className="auth-switch">
<span>Уже есть аккаунт? <a href="/login">Войти</a></span>
Уже есть аккаунт? <a href="/login">Войти</a>
</div>
</div>
</div>
);
}
export default Register;

46
src/pages/mockFetch.js Normal file
View File

@@ -0,0 +1,46 @@
export function mockFetch(url, options) {
//имитируем асинхронность
return new Promise((resolve) => {
// задержка 500 мс, запрос "обрабатывается"
setTimeout(() => {
// извлекаем метод запроса,тело запроса (данные)
const { method, body } = options;
// если тело есть => преобразуем его из JSON-строки в объект
const data = body ? JSON.parse(body) : null;
if (url === '/api/register' && method === 'POST') {
// Возвращаем успешный ответ
resolve({
ok: true, // статус успешного ответа
json: () => Promise.resolve({ message: 'Регистрация успешна' }),
});
} else if (url === '/api/login' && method === 'POST') {
// Проверяем, совпадают ли логин и пароль
if (data.login === '123' && data.password === '123') {
// Если совпадают - возвращаем успешный ответ с "токеном"
resolve({
ok: true,
json: () => Promise.resolve({ token: 'fake-token' }),
});
} else {
// Если нет - возвращаем ошибку с сообщением
resolve({
ok: false,
json: () => Promise.resolve({ message: 'Неверный логин или пароль' }),
});
}
// Если запрос на неизвестный адрес или с другим методом
} else {
// Возвращаем ошибку
resolve({
ok: false,
json: () => Promise.resolve({ message: 'Неизвестный адрес' }),
});
}
}, 500);
});
}