.
This commit is contained in:
@@ -4,42 +4,42 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: calc(100vh - 160px);
|
min-height: calc(100vh - 160px);
|
||||||
padding: 40px 0;
|
padding: 40px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-container {
|
.auth-container {
|
||||||
background: white;
|
background: white;
|
||||||
padding: 40px;
|
padding: 40px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
width: 400px;
|
width: 400px;
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-container h2 {
|
.auth-container h2 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
color: #2c3e50;
|
color: #2c3e50;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group label {
|
.form-group label {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group input {
|
.form-group input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 12px;
|
padding: 5px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-btn {
|
.auth-btn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 14px;
|
padding: 14px;
|
||||||
background: #6C63FF;
|
background: #6C63FF;
|
||||||
@@ -49,16 +49,15 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-switch {
|
.auth-switch {
|
||||||
margin-top: 25px;
|
margin-top: 25px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #7f8c8d;
|
color: #7f8c8d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-switch a {
|
.auth-switch a {
|
||||||
color: #6C63FF;
|
color: #6C63FF;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,78 +1,85 @@
|
|||||||
import React, { useState } from 'react'; // Хук состояния
|
import React, { useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { mockFetch } from './mockFetch';
|
||||||
import './AuthForms.css';
|
import './AuthForms.css';
|
||||||
|
|
||||||
function Login() {
|
export default function Login() {
|
||||||
// Состояние для хранения данных формы
|
const [formData, setFormData] = useState({ login: '', password: '' }); // Состояние для хранения данных формы
|
||||||
const [formData, setFormData] = useState({
|
const [error, setError] = useState(null);// для хранения сообщения об ошибке
|
||||||
email: '',
|
|
||||||
password: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
// Хук для программной навигации
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
// Обработчик изменений в полях ввода
|
// Функция, которая вызывается при изменении любого поля формы, обновляет соответствующее поле в formData и сбрасывает ошибку
|
||||||
const handleChange = (e) => {
|
const handleChange = e => {
|
||||||
const { name, value } = e.target;
|
setFormData(prev => ({ ...prev, [e.target.name]: e.target.value }));
|
||||||
setFormData(prev => ({
|
setError(null);
|
||||||
...prev, // Сохранение предыдущих значений
|
|
||||||
[name]: value // Динамическое обновление поля
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Обработчик отправки формы
|
// Функция, которая вызывается при отправке формы
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = async e => {
|
||||||
e.preventDefault(); // Отмена стандартного поведения
|
e.preventDefault(); // Отменяем стандартное поведение формы (перезагрузку страницы)
|
||||||
console.log('Вход:', formData); // Логирование данных (в реальном приложении - запрос к API)
|
|
||||||
navigate('/'); // Перенаправление на главную страницу
|
// Отправляем данные формы через 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 (
|
return (
|
||||||
// Основной контейнер страницы
|
|
||||||
<div className="auth-page">
|
<div className="auth-page">
|
||||||
<div className="auth-container">
|
<div className="auth-container">
|
||||||
<h2>Вход</h2>
|
<h2>Вход</h2>
|
||||||
|
|
||||||
|
{error && <p style={{ color: 'red', textAlign: 'center' }}>{error}</p>}
|
||||||
|
|
||||||
{/* Форма с обработчиком отправки */}
|
{/* Форма с обработчиком отправки */}
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
{/* Группа полей для email */}
|
{/* Поле для ввода логина */}
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label>Email</label>
|
<label htmlFor="login">Логин</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
id="login"
|
||||||
name="email"
|
name="login"
|
||||||
value={formData.email}
|
type="text"
|
||||||
onChange={handleChange}
|
value={formData.login} // Значение из состояния
|
||||||
required // Обязательное поле
|
onChange={handleChange} // Обновляем состояние при изменении
|
||||||
|
required // Поле обязательно для заполнения
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Группа полей для пароля */}
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label>Пароль</label>
|
<label htmlFor="password">Пароль</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
id="password"
|
||||||
name="password"
|
name="password"
|
||||||
|
type="password"
|
||||||
value={formData.password}
|
value={formData.password}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Кнопка отправки формы */}
|
<button type="submit" className="auth-btn">Войти</button>
|
||||||
<button type="submit" className="auth-btn">
|
|
||||||
Войти
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* Ссылка для перехода к регистрации */}
|
|
||||||
<div className="auth-switch">
|
<div className="auth-switch">
|
||||||
<span>Нет аккаунта? <a href="/register">Создать</a></span>
|
Нет аккаунта? <a href="/register">Зарегистрироваться</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Login;
|
|
||||||
|
|||||||
@@ -1,36 +1,41 @@
|
|||||||
import React, { useState } from 'react'; //для управления состоянием формы
|
import React, { useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { mockFetch } from './mockFetch';
|
||||||
import './AuthForms.css';
|
import './AuthForms.css';
|
||||||
|
|
||||||
function Register() {
|
export default function Register() {
|
||||||
// Состояние для хранения данных формы
|
// Состояние для хранения данных формы: логин, email и пароль
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({ login: '', email: '', password: '' });
|
||||||
name: '',
|
const [error, setError] = useState(null);
|
||||||
email: '',
|
const navigate = useNavigate(); //для программного перехода на другую страницу
|
||||||
password: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
// Хук для навигации между страницами
|
// Функция вызывается при изменении любого поля формы, обновляет соответствующее поле в formData и сбрасывает ошибку
|
||||||
const navigate = useNavigate();
|
const handleChange = e => {
|
||||||
|
setFormData(prev => ({ ...prev, [e.target.name]: e.target.value }));
|
||||||
// Обработчик изменений в полях ввода
|
setError(null);
|
||||||
const handleChange = (e) => {
|
|
||||||
const { name, value } = e.target; // Извлекаем имя поля и значение
|
|
||||||
setFormData(prev => ({
|
|
||||||
...prev, // Копируем предыдущее состояние
|
|
||||||
[name]: value // Обновляем конкретное поле
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Обработчик отправки формы
|
// Функция вызывается при отправке формы
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = async e => {
|
||||||
e.preventDefault(); // Отменяем стандартное поведение формы
|
e.preventDefault(); // Отменяем перезагрузку страницы
|
||||||
|
|
||||||
// В реальном приложении здесь будет запрос к API
|
// Отправляем данные формы через mockFetch на "адрес" /api/register методом POST
|
||||||
console.log('Регистрация:', formData);
|
const response = await mockFetch('/api/register', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' }, // Заголовок, что данные в формате JSON
|
||||||
|
body: JSON.stringify(formData), // Преобразуем объект formData в JSON-строку
|
||||||
|
});
|
||||||
|
|
||||||
// Перенаправляем на главную страницу
|
const data = await response.json(); // для программного перехода на другую страницу
|
||||||
navigate('/');
|
|
||||||
|
if (response.ok) {
|
||||||
|
// Если регистрация успешна, показываем сообщение и переходим на страницу входа
|
||||||
|
alert(data.message);
|
||||||
|
navigate('/login');
|
||||||
|
} else {
|
||||||
|
// Если произошла ошибка, сохраняем её в состоянии для отображения
|
||||||
|
setError(data.message);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -38,56 +43,54 @@ function Register() {
|
|||||||
<div className="auth-container">
|
<div className="auth-container">
|
||||||
<h2>Регистрация</h2>
|
<h2>Регистрация</h2>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit}> {/* Форма с обработчиком отправки */}
|
{error && <p style={{ color: 'red', textAlign: 'center' }}>{error}</p>}
|
||||||
{/* Группа полей для имени */}
|
|
||||||
|
{/* Форма с обработчиком отправки */}
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label>Имя</label>
|
<label htmlFor="login">Логин</label>
|
||||||
<input
|
<input
|
||||||
|
id="login"
|
||||||
|
name="login"
|
||||||
type="text"
|
type="text"
|
||||||
name="name"
|
value={formData.login} // Значение из состояния
|
||||||
value={formData.name} // Привязка к состоянию
|
onChange={handleChange} // Обработчик изменения
|
||||||
onChange={handleChange} // Обработчик изменений
|
required // Поле обязательно для заполнения
|
||||||
required // Обязательное поле
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Группа полей для email */}
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label>Email</label>
|
<label htmlFor="email">Email</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
id="email"
|
||||||
name="email"
|
name="email"
|
||||||
|
type="email"
|
||||||
value={formData.email}
|
value={formData.email}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Группа полей для пароля */}
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label>Пароль</label>
|
<label htmlFor="password">Пароль</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
id="password"
|
||||||
name="password"
|
name="password"
|
||||||
|
type="password"
|
||||||
value={formData.password}
|
value={formData.password}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Кнопка отправки формы */}
|
<button type="submit" className="auth-btn">Зарегистрироваться</button>
|
||||||
<button type="submit" className="auth-btn">
|
|
||||||
Зарегистрироваться
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* Ссылка для перехода к авторизации */}
|
|
||||||
<div className="auth-switch">
|
<div className="auth-switch">
|
||||||
<span>Уже есть аккаунт? <a href="/login">Войти</a></span>
|
Уже есть аккаунт? <a href="/login">Войти</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Register;
|
|
||||||
|
|||||||
46
src/pages/mockFetch.js
Normal file
46
src/pages/mockFetch.js
Normal 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user