diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 660a8c9..0000000 --- a/src/App.css +++ /dev/null @@ -1,539 +0,0 @@ - - -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -@font-face { - font-family: "Roboto Regular"; - src: url("./fonts/roboto-regular/roboto-regular.svg") format("svg"); - src: url("./fonts/roboto-regular/roboto-regular.ttf") format("truetype"); - src: url("./fonts/roboto-regular/roboto-regular.woff") format("woff"); - src: url("./fonts/roboto-regular/roboto-regular.woff2") format("woff2"); - font-weight: normal; - font-style: normal; -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -.switch-link { - margin-top: 15px; - text-align: center; -} - -.switch-link button { - background: none; - border: none; - color: #007bff; - cursor: pointer; - font-size: 14px; - text-decoration: underline; -} - -body { - font-family: 'Roboto Regular'; - margin: 0; - padding: 0; - background-color: #33404d; -} - -body * { transition: all .4s ease; } - -ul{ - list-style-type: none; - padding: 0px; -} - -.app { - max-width: 800px; - margin: 0 auto; - padding: 20px; -} - -/* Страница входа */ -.login-page { - background-color: #1f2430; - border-radius: 8px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); - padding: 20px; - margin: 50px auto; - max-width: 400px; -} - -.profile-page { - background-color: #1f2430; - border-radius: 8px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); - padding: 20px; - margin: 10px auto; - max-width: 1200px; -} - -h2 { - text-align: center; - color: #CAD1D8; - margin-bottom: 20px; -} - -p { - text-align: center; - color: #CAD1D8; - margin-bottom: 0px; -} - -.modal-content p { - text-align: left -} - -.modal-content div { - margin-bottom: 20px -} -.text-block { - text-align: left; - color: #999999; - margin-bottom: 2em; -} - -.com { - color: #999999; - text-align: left; - margin: 10px 0px 10px 0px; - margin-bottom: auto; -} - -.com modal-content { - text-align: left; - color: #999999; - margin: 10px 0px 10px 0px; - margin-bottom: auto; -} - -.modal-content input{ - margin: 10px 0px; -} - -.modal-content div{ - margin: 10px 0px; -} - -.user-info p { - text-align: left; - color: #CAD1D8; - margin: 15px 0; - font-size: 20px; -} - -form div { - margin-bottom: 15px; -} - -label { - display: block; - margin-bottom: 5px; - font-weight: bold; - color: #CAD1D8; -} - -input[type="text"], -input[type="password"] { - width: 100%; - padding: 10px; - border: 1px solid #ddd; - border-radius: 4px; - box-sizing: border-box; -} - -.Important-button:hover { - background-color: #cb0101; -} - -.Important-button { - width: 100%; - padding: 12px; - margin: 8px; - background-color: #e30000; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; - font-size: 16px; -} - -button { - width: 100%; - padding: 12px; - margin: 10px auto; - background-color: #007bff; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; - font-size: 16px; -} - -.frame { - background-color: #33404d; - margin: 10px 0px; - width: 30%; - padding: 6px; - border-radius: 6px; - font-size: 16px; - border: 2px solid #999999 -} - -.frame p { - font-size: 16px; -} - -.frame:hover { - border-color: #CAD1D8; -} - -button:hover { - background-color: #0056b3; -} - -button:disabled { - background-color: #6c757d; - cursor: not-allowed; -} - -/* Сообщения об ошибках */ -.error { - background-color: #f8d7da; - color: #721c24; - padding: 10px; - border-radius: 4px; - margin-bottom: 15px; - text-align: center; -} - -/* Страница профиля */ -.form-group { - margin-bottom: 10px; -} - -.form-group label { - text-align: left; - display: block; - margin-bottom: 5px; - font-weight: 500; -} - -.form-group input { - width: 100%; - padding: 8px; - border: 1px solid #ddd; - border-radius: 4px; -} - -.modal-buttons { - display: flex; - gap: 10px; - margin-top: 20px; -} - -.button-small { - width: 30%; - min-width: auto; - height: auto; -} - -.user-info p { - text-align: left; - margin: 5px 0px 5px 0px; - font-size: 20px; -} - -.buttonName { - display: flex; -} - -.buttonName button{ - background-color: #007bff; - margin: 10px 5px; - width: 5%; - padding: 6px; - border-radius: 6px; - font-size: 20px; -} - -.buttonName button:hover { - background-color: #0056b3; -} - -.com p { - color: #CAD1D8; - font-size: 18px; -} - - - -.kan-ban-list-sort{ - background-color: #2b3245; - padding: 10px; - border-radius: 6px; - margin-bottom: 20px; -} - -h3 { - text-align: left; - color: #CAD1D8; - margin: 0px; -} - -.nav-sort{ - display: flex; -} - -.nav-sort button+button{ - margin-left: 10px -} - -.kan-ban-list { - background-color: #2b3245; - padding: 10px; - border-radius: 6px; -} - -.kan-ban-list .inf { - padding: 0px 0px; - display: flex; - justify-content: space-between; - align-items: center; -} - -.kan-ban-list .inf button{ - width: 200px; - margin: 0px; -} - - -.kan-ban-list ul { - margin: 0px -} - -.kan-ban-list ul button{ - border-radius: 6px; - display: flex; - flex-direction: column; - justify-content: space-around; - background-color: #3d4763;; -} - -.kan-ban-list ul button:hover{ - box-shadow: 0 0 10px 2px #08e8de78; -} - -.kan-ban-list .sort-row{ - display: flex; - justify-content: space-between; -} - -.sort-row p, .sort-row h3{ - margin: 4px 0px; -} - -.sort-row+.sort-row p { - margin: 16px 0px 0px 0px; -} - - - - - - - - - - - - - - - - - -/*header*/ - -.nav-avatar { - height: 32px; - height: 32px; - margin-left: 8px; - border-radius: 1000px -} - -.header { - background-color: #1f2430; - padding: 0; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - height: 56px; -} - -.header-container { - max-width: 1200px; - margin: 0 auto; - display: flex; - justify-content: space-between; - align-items: center; - padding: 0 1rem; - height: 56px; -} - -.logo h1 { - font-family: 'Roboto Regular'; - margin: 0; - font-size: 24px; - color: #CAD1D8; - text-decoration: none; -} - -h1:hover { - color: white; -} - -.logo a { - text-decoration: none; -} - -.nav-list { - opacity: 0; - display: flex; - list-style: none; - margin: 0; - padding: 0; -} - -.nav-list.visible { - opacity: 1; -} - -.nav-list li { - - padding: 0 1rem; - height: 56px; - display: flex; - align-items: center; -} - -.nav-list li:hover { - box-shadow: #08e8de 0px -2px inset; - background-color: rgba(0, 0, 0, 0.25) ; -} - -.nav-list a { - text-decoration: none; - color: #CAD1D8; - display: flex; - align-items: center; - font-size: 18px; - height: 56px; -} - -.nav-list a:hover { - color: white; -} - - - - - - - - - - - - - -/* Стили для модального окна */ -.confirm-modal { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.8); - display: flex; - justify-content: center; - align-items: center; -} - -.modal-content { - background: #1f2430; - padding: 20px; - border-radius: 8px; - text-align: center; - min-width: 300px; -} - -.modal-buttons { - display: flex; - justify-content: space-between; - margin-top: 20px 15px; -} - -.modal-buttons button { - padding: 10px 20px; - border: none; - border-radius: 4px; - cursor: pointer; - margin: 8px; -} - -.modal-buttons button:first-child { - background: #e30000; - color: white; -} - -.modal-buttons button:last-child { - background: #007bff; - color: white; -} - -.modal-buttons button:hover { - background-color: #cb0101 -} - -.modal-buttons button:last-child:hover { - background-color: #0056b3 - -} - - - - - diff --git a/src/App.js b/src/App.js index 813d7ba..6650ee2 100644 --- a/src/App.js +++ b/src/App.js @@ -1,6 +1,6 @@ import logo from './logo.svg'; -import './App.css'; -import React from 'react'; +import './css/App.css'; +import './css/Modal.css'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; // Исправленный импорт import Login from './Login'; import Profile from './Profile'; @@ -13,17 +13,17 @@ import OtherProfile from './OtherProfile'; function App() { return ( - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - {/* Корректный редирект на страницу входа */} - } /> - + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + {/* Корректный редирект на страницу входа */} + } /> + ); } diff --git a/src/Header.js b/src/Header.js index cbb9b76..40baaca 100644 --- a/src/Header.js +++ b/src/Header.js @@ -1,6 +1,7 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import axios from 'axios'; +import './css/Header.css'; const Header = () => { const [display_name, setDisplay_name] = useState(''); @@ -22,32 +23,36 @@ const Header = () => { }, []); return ( -
-
-
- -

Fool-stack

- -
- -
-
+
+
+
+ +

Fool-stack

+ +
+ +
+
); }; diff --git a/src/KBBoard.js b/src/KBBoard.js index 5f43aa1..b59b347 100644 --- a/src/KBBoard.js +++ b/src/KBBoard.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import { useParams } from 'react-router-dom'; import axios from 'axios'; import Header from './Header'; diff --git a/src/Login.js b/src/Login.js index 0523f47..30de198 100644 --- a/src/Login.js +++ b/src/Login.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import axios from 'axios'; import { useNavigate } from 'react-router-dom'; import Header from './Header'; @@ -20,14 +20,7 @@ const Login = () => { setLoading(true); try { const newUser = { username, password }; - await axios.post('/api/users/login', newUser, - { - withCredentials: true - /*headers: { - 'Content-Type': 'application/json' - }*/ - } - ); + await axios.post('/api/users/login', newUser, { withCredentials: true }); setTimeout(() => { navigate('/profile'); }, 500); @@ -38,43 +31,43 @@ const Login = () => { } }; - return ( - <> -
-
-

Вход в систему

- { - error &&
{error}
- } -
-
- - setUsername(e.target.value)} - required - /> + return ( + <> +
+
+

Вход в систему

+ { + error &&
{error}
+ } + +
+ + setUsername(e.target.value)} + required + /> +
+
+ + setPassword(e.target.value)} + required + /> +
+ + +
-
- - setPassword(e.target.value)} - required - /> -
- - - -
- - ); + + ); }; export default Login; \ No newline at end of file diff --git a/src/Mainpage.js b/src/Mainpage.js index 24fde77..a771ced 100644 --- a/src/Mainpage.js +++ b/src/Mainpage.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import axios from 'axios'; import Header from './Header'; @@ -7,10 +7,12 @@ const Mainpage = () => { const [error, setError] = useState(''); return ( - <>
-
- -
+ <> +
+
+ +
+ ); } diff --git a/src/OtherProfile.js b/src/OtherProfile.js index 7de5494..512f007 100644 --- a/src/OtherProfile.js +++ b/src/OtherProfile.js @@ -1,4 +1,4 @@ -import React, {useState, useEffect} from 'react'; +import {useState, useEffect} from 'react'; import './css/OtherProfile.css'; import {useParams, useNavigate} from 'react-router-dom'; import axios from 'axios'; diff --git a/src/Profile.js b/src/Profile.js index c1d0272..75ce354 100644 --- a/src/Profile.js +++ b/src/Profile.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import axios from 'axios'; import { useNavigate } from 'react-router-dom'; import Header from './Header'; @@ -29,18 +29,18 @@ const Profile = () => { // Если нет сессии - редирект на логин setError('Вы не авторизованы'); setTimeout(() => { - window.location.href = '/login'; + navigate('/login'); }, 1500); } }; checkSession(); - }, []); + }, [navigate]); const handleLogout = async () => { try { await axios.post('/api/users/logout'); setUser(null); - window.location.href = '/login'; // Редирект после выхода + navigate('/login'); // Редирект после выхода } catch (err) { setError('Ошибка'); } @@ -100,28 +100,21 @@ const Profile = () => { } }; - const changePassword = async (e) => { - e.preventDefault(); - setPasswordError(''); + const changePassword = async (e) => { + e.preventDefault(); + setPasswordError(''); - try { - const NewPassword = {old_password, new_password, new_password_confirm} - await axios.put('/api/users/change_password', - NewPassword - , { - withCredentials: true - }); - - alert('Пароль успешно изменён!'); - setShowChangePassword(false); - setold_password(''); - setnew_password(''); - setnew_password_confirm(''); - } catch (err) { - setPasswordError( - err.response?.data?.detail || 'Ошибка при смене пароля' - ); - } + try { + const NewPassword = {old_password, new_password, new_password_confirm} + await axios.put('/api/users/change_password', NewPassword, { withCredentials: true }); + alert('Пароль успешно изменён!'); + setShowChangePassword(false); + setold_password(''); + setnew_password(''); + setnew_password_confirm(''); + } catch (err) { + setPasswordError( err.response?.data?.detail || 'Ошибка при смене пароля' ); + } }; @@ -151,11 +144,9 @@ const Profile = () => { const deleteAccount = async () => { try { - await axios.delete('/api/users/me', { - withCredentials: true - }); + await axios.delete('/api/users/me', { withCredentials: true }); setUser(null); - window.location.href = '/login'; + navigate('/login'); setShowConfirm(false); // Закрываем окно после удаления } catch (err) { setError('Ошибка удаления'); @@ -163,152 +154,151 @@ const Profile = () => { } }; - return ( - <>
-
+ return ( + <> +
+
+ { + error &&
{error}
+ } + {user && ( +
+

Привет, {user}! Добро пожаловать в личный кабинет.

+
Здесь ты сможешь управлять данными своей учётной записи.
+

Информация об учётной записи

+
Отображаемое имя
+
+

{user}

+ +
+
Логин
+
+

{userName}

+ +
+

Изменить пароль

+
В целях безопасности мы рекомендуем выбрать пароль, который ещё не использовался вами в других учётных записях.
+ + + +
+ )} + + {ShowConfirmUserName && ( +
+
+

Обновите логин

+

Текущий логин: {userName}

+
Новый логин
+
+
+ setnew_username(e.target.value)} + required + /> +
+ +
+ +
+
+ )} + + {ShowConfirmName && ( +
+
+

Обновите отображаемое имя

+

Текущее отображаемое имя: {user}

+
Новое отображаемое имя
+
+
+ setnew_display_name(e.target.value)} + required + /> +
+ +
+ +
+
+ )} + + {showChangePassword && ( +
+
+

Изменить пароль

+ + {passwordError && ( +
+ {passwordError} +
+ )} - { - error &&
{error}
- } +
+
+ + setold_password(e.target.value)} + required + /> +
- {user && ( -
-

Привет, {user}! Добро пожаловать в личный кабинет.

-
Здесь ты сможешь управлять данными своей учётной записи.
-

Информация об учётной записи

-
Отображаемое имя
-
-

{user}

- -
-
Логин
-
-

{userName}

- -
-

Изменить пароль

-
В целях безопасности мы рекомендуем выбрать пароль, который ещё не использовался вами в других учётных записях.
- - - -
- )} - - {ShowConfirmUserName && ( -
-
-

Обновите логин

-

Текущий логин: {userName}

-
Новый логин
- -
- setnew_username(e.target.value)} - required - /> +
+ + setnew_password(e.target.value)} + required + /> +
+ +
+ + setnew_password_confirm(e.target.value)} + required + /> +
+ +
+ + +
+ +
+
+ )} + + {/* Всплывающее окно подтверждения */} + {showConfirm && ( +
+
+

Вы действительно хотите удалить аккаунта?

+
+ + +
+
+
+ )}
- - - -
-
- )} - - {ShowConfirmName && ( -
-
-

Обновите отображаемое имя

-

Текущее отображаемое имя: {user}

-
Новое отображаемое имя
-
-
- setnew_display_name(e.target.value)} - required - /> -
- -
- -
-
- )} - - {showChangePassword && ( -
-
-

Изменить пароль

- - {passwordError && ( -
- {passwordError} -
- )} - -
-
- - setold_password(e.target.value)} - required - /> -
- -
- - setnew_password(e.target.value)} - required - /> -
- -
- - setnew_password_confirm(e.target.value)} - required - /> -
- -
- - -
-
-
-
-)} - - {/* Всплывающее окно подтверждения */} - {showConfirm && ( -
-
-

Вы действительно хотите удалить аккаунта?

-
- - -
-
-
- )} -
- ); + + ); }; export default Profile; \ No newline at end of file diff --git a/src/Registration.js b/src/Registration.js index 007302a..a0946b3 100644 --- a/src/Registration.js +++ b/src/Registration.js @@ -26,7 +26,6 @@ const Registration = () => { setPassword(''); setPassword_confirm(''); } catch (err) { - // Обрабатываем ошибки от сервера (например, дубликат password) setError(err.response.data.detail || 'Пароль должен иметь длинну от 8 до 16 символов, содержать заглавные и строчные буквы, цифры и спец символ(_-?.!@\'`)'); } finally { setLoading(false); @@ -81,7 +80,7 @@ const Registration = () => { />