diff --git a/src/pages/AuthForms.css b/src/pages/AuthForms.css index 6879d59..b5ae10e 100644 --- a/src/pages/AuthForms.css +++ b/src/pages/AuthForms.css @@ -1,64 +1,63 @@ .auth-page { - 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 h2 { - margin-top: 0; - color: #2c3e50; - text-align: center; - } - - .form-group { - margin-bottom: 20px; - } - - .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; - } - - .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; - } - \ No newline at end of file + 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 h2 { + margin-top: 0; + color: #2c3e50; + text-align: center; +} + +.form-group { + margin-bottom: 20px; +} + +.form-group label { + display: block; + margin-bottom: 8px; + font-weight: 500; +} + +.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-switch { + margin-top: 25px; + text-align: center; + color: #7f8c8d; +} + +.auth-switch a { + color: #6C63FF; + text-decoration: none; +} diff --git a/src/pages/Login.js b/src/pages/Login.js index b037b3b..9541088 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -1,78 +1,85 @@ -import React, { useState } from 'react'; // Хук состояния -import { useNavigate } from 'react-router-dom'; -import './AuthForms.css'; +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 ( - // Основной контейнер страницы -
-
-

Вход

- +
+
+

Вход

+ + {error &&

{error}

} + {/* Форма с обработчиком отправки */}
- {/* Группа полей для email */} + {/* Поле для ввода логина */}
- +
- - {/* Группа полей для пароля */} +
- +
- - {/* Кнопка отправки формы */} - + +
- - {/* Ссылка для перехода к регистрации */} +
- Нет аккаунта? Создать + Нет аккаунта? Зарегистрироваться
); } - -export default Login; diff --git a/src/pages/Register.js b/src/pages/Register.js index 944f3a1..937b952 100644 --- a/src/pages/Register.js +++ b/src/pages/Register.js @@ -1,93 +1,96 @@ -import React, { useState } from 'react'; //для управления состоянием формы -import { useNavigate } from 'react-router-dom'; -import './AuthForms.css'; +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: '' - }); - - // Хук для навигации между страницами - const navigate = useNavigate(); +export default function Register() { + // Состояние для хранения данных формы: логин, email и пароль + const [formData, setFormData] = useState({ login: '', email: '', 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(); // Отменяем стандартное поведение формы + // Функция вызывается при отправке формы + const handleSubmit = async e => { + e.preventDefault(); // Отменяем перезагрузку страницы + + // Отправляем данные формы через mockFetch на "адрес" /api/register методом POST + const response = await mockFetch('/api/register', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, // Заголовок, что данные в формате JSON + body: JSON.stringify(formData), // Преобразуем объект formData в JSON-строку + }); - // В реальном приложении здесь будет запрос к API - console.log('Регистрация:', formData); - - // Перенаправляем на главную страницу - navigate('/'); + const data = await response.json(); // для программного перехода на другую страницу + + if (response.ok) { + // Если регистрация успешна, показываем сообщение и переходим на страницу входа + alert(data.message); + navigate('/login'); + } else { + // Если произошла ошибка, сохраняем её в состоянии для отображения + setError(data.message); + } }; return ( -
-
-

Регистрация

- -
{/* Форма с обработчиком отправки */} - {/* Группа полей для имени */} +
+
+

Регистрация

+ + {error &&

{error}

} + + {/* Форма с обработчиком отправки */} + +
- +
- - {/* Группа полей для email */} +
- +
- - {/* Группа полей для пароля */} +
- +
- - {/* Кнопка отправки формы */} - + + - - {/* Ссылка для перехода к авторизации */} +
- Уже есть аккаунт? Войти + Уже есть аккаунт? Войти
); } - -export default Register; diff --git a/src/pages/mockFetch.js b/src/pages/mockFetch.js new file mode 100644 index 0000000..2b137ab --- /dev/null +++ b/src/pages/mockFetch.js @@ -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); + }); + } + \ No newline at end of file