Merge pull request #147 from apuc/registration

Registration
This commit is contained in:
NikoM1k 2023-11-08 22:04:54 +03:00 committed by GitHub
commit 8c513b5be9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 296 additions and 46 deletions

View File

@ -35,7 +35,7 @@ export const apiRequest = (
.then( .then(
(response) => (response) =>
new Promise((resolve) => { new Promise((resolve) => {
if (response.data.redirect || response.status === 401) { if (response.data?.redirect || response.status === 401) {
window.location.replace("/auth"); window.location.replace("/auth");
localStorage.clear(); localStorage.clear();
// dispatch(auth(false)); // dispatch(auth(false));

View File

@ -31,7 +31,7 @@ export const AuthBlock = ({ title, description, img, resetModal }) => {
> >
Войти Войти
</button> </button>
<span onClick={() => resetModal(true)}>Вспомнить пароль</span> <span onClick={() => resetModal(true)}>Восстановить пароль</span>
</div> </div>
</form> </form>
{img && <img src={img} alt="authImg" className="auth__img" />} {img && <img src={img} alt="authImg" className="auth__img" />}

View File

@ -11,6 +11,7 @@ import { apiRequest } from "@api/request";
import { Loader } from "@components/Common/Loader/Loader"; import { Loader } from "@components/Common/Loader/Loader";
import ModalErrorLogin from "@components/Modal/ModalErrorLogin/ModalErrorLogin"; import ModalErrorLogin from "@components/Modal/ModalErrorLogin/ModalErrorLogin";
import ModalRegistration from "@components/Modal/ModalRegistration/ModalRegistration"; import ModalRegistration from "@components/Modal/ModalRegistration/ModalRegistration";
import ModalResetPassword from "@components/Modal/ModalResetPassword/ModalResetPassword";
import authHead from "assets/icons/authHead.svg"; import authHead from "assets/icons/authHead.svg";
import eyePassword from "assets/icons/passwordIcon.svg"; import eyePassword from "assets/icons/passwordIcon.svg";
@ -27,6 +28,7 @@ export const AuthBox = ({ title }) => {
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [modalError, setModalError] = useState(false); const [modalError, setModalError] = useState(false);
const [modalReset, setModalReset] = useState(false);
const [modalReg, setModalReg] = useState(false); const [modalReg, setModalReg] = useState(false);
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);
@ -120,8 +122,10 @@ export const AuthBox = ({ title }) => {
> >
{isLoading ? <Loader /> : "Войти"} {isLoading ? <Loader /> : "Войти"}
</button> </button>
<span className="auth-box__reset">Вспомнить пароль</span> <span className="auth-box__reset" onClick={() => setModalReset(true)}>
Восстановить пароль
</span>
<ModalResetPassword active={modalReset} setActive={setModalReset} />
<ModalRegistration active={modalReg} setActive={setModalReg} /> <ModalRegistration active={modalReg} setActive={setModalReg} />
</div> </div>
<p className="auth-box__registration"> <p className="auth-box__registration">

View File

@ -38,6 +38,20 @@ export const ModalRegistration = ({ active, setActive }) => {
const { showNotification } = useNotification(); const { showNotification } = useNotification();
const submitHandler = () => { const submitHandler = () => {
if (!inputsValue.password || !inputsValue.userName || !inputsValue.email) {
return showNotification({
show: true,
text: "Введите коректные данные",
type: "error",
});
}
if (!validateEmail(inputsValue.email)) {
return showNotification({
show: true,
text: "Введите коректный email",
type: "error",
});
}
apiRequest("/register/sign-up", { apiRequest("/register/sign-up", {
method: "POST", method: "POST",
data: { data: {
@ -45,7 +59,14 @@ export const ModalRegistration = ({ active, setActive }) => {
email: inputsValue.email, email: inputsValue.email,
password: inputsValue.password, password: inputsValue.password,
}, },
}).then(() => { }).then((data) => {
if (!data) {
showNotification({
show: true,
text: "Аккаунт с таким логином или email уже существует",
type: "error",
});
} else {
setActive(false); setActive(false);
resetInputsValue(); resetInputsValue();
showNotification({ showNotification({
@ -53,6 +74,7 @@ export const ModalRegistration = ({ active, setActive }) => {
text: "Аккаунт успешно создан", text: "Аккаунт успешно создан",
type: "success", type: "success",
}); });
}
}); });
}; };
return ( return (
@ -113,13 +135,7 @@ export const ModalRegistration = ({ active, setActive }) => {
e.preventDefault(); e.preventDefault();
submitHandler(); submitHandler();
}} }}
styles={ styles="button-box__submit"
inputsValue.userName &&
validateEmail(inputsValue.email) &&
inputsValue.password
? "button-box__submit"
: "button-box__submit disable"
}
> >
Отправить Отправить
</BaseButton> </BaseButton>

View File

@ -0,0 +1,165 @@
import React, { useState } from "react";
import { apiRequest } from "@api/request";
import { useNotification } from "@hooks/useNotification";
import ModalLayout from "@components/Common/ModalLayout/ModalLayout";
import arrow from "assets/icons/arrows/arrowCalendar.png";
import close from "assets/icons/close.png";
import "./modalResetPassword.scss";
export const ModalResetPassword = ({ active, setActive }) => {
const [step, setStep] = useState(false);
const [inputsValue, setInputsValue] = useState({
email: "",
token: "",
password: "",
});
const validateEmail = (email) => {
// регулярное выражение для проверки email
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
// возвращаем true, если email проходит проверку, и false, если нет
return re.test(email);
};
const resetInputsValue = () => {
setInputsValue({
email: "",
token: "",
password: "",
});
};
const { showNotification } = useNotification();
const submitHandler = () => {
if (!validateEmail(inputsValue.email)) {
return showNotification({
show: true,
text: "Введите коректный email",
type: "error",
});
}
apiRequest("/register/request-password-reset", {
method: "POST",
data: {
email: inputsValue.email,
},
}).then((data) => {
if (data) {
showNotification({
show: true,
text: "Письмо отправлено Вам на почту",
type: "success",
});
setStep(true);
}
});
};
const resetPassword = () => {
if (!inputsValue.password || !inputsValue.token) {
return showNotification({
show: true,
text: "Введите данные",
type: "error",
});
}
apiRequest("/register/reset-password", {
method: "POST",
data: {
token: inputsValue.token,
password: inputsValue.password,
},
}).then(() => {
setActive(false);
resetInputsValue();
showNotification({
show: true,
text: "Пароль изменён",
type: "success",
});
});
};
return (
<ModalLayout active={active} setActive={setActive}>
<div className="resetPassword">
<img
className="resetPassword__close"
src={close}
alt="close"
onClick={() => setActive(false)}
/>
<h3 className="resetPassword__title">Восстановление пароля</h3>
{!step ? (
<div className="resetPassword__email">
<h5>Введите email:</h5>
<input
type="email"
onChange={(e) =>
setInputsValue((prevValue) => ({
...prevValue,
email: e.target.value,
}))
}
placeholder="Email"
/>
<button
className="resetPassword__btn"
onClick={(e) => {
e.preventDefault();
submitHandler();
}}
>
Отправить
</button>
</div>
) : (
<div className="resetPassword__email">
<img
src={arrow}
onClick={() => setStep(false)}
className="resetPassword__email__arrow"
/>
<h5>Введите код подтверждения:</h5>
<input
type="text"
onChange={(e) =>
setInputsValue((prevValue) => ({
...prevValue,
token: e.target.value,
}))
}
placeholder="token"
/>
<h5>Введите новый пароль:</h5>
<input
type="password"
onChange={(e) =>
setInputsValue((prevValue) => ({
...prevValue,
password: e.target.value,
}))
}
placeholder="password"
/>
<button
className="resetPassword__btn"
onClick={(e) => {
e.preventDefault();
resetPassword();
}}
>
Отправить
</button>
</div>
)}
</div>
</ModalLayout>
);
};
export default ModalResetPassword;

View File

@ -0,0 +1,63 @@
.resetPassword {
width: 370px;
position: relative;
&__close {
width: 20px;
height: 20px;
cursor: pointer;
position: absolute;
top: -10px;
right: -10px;
}
&__title {
font-size: 20px;
text-align: center;
margin-bottom: 15px;
}
&__email {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
h5 {
font-size: 16px;
margin-bottom: 10px;
}
input {
padding: 10px !important;
height: 40px !important;
margin-bottom: 15px !important;
}
&__arrow {
position: absolute;
width: 20px;
transform: rotate(180deg);
left: -10px;
top: -55px;
cursor: pointer;
}
}
&__btn {
width: 100px;
height: 35px;
border-radius: 44px;
display: flex;
justify-content: center;
align-items: center;
background-color: #ffffff;
background-image: linear-gradient(to top, #6aaf5c 0%, #52b709 100%), linear-gradient(36deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.16) 47%, rgba(255, 255, 255, 0.17) 50%, rgba(255, 255, 255, 0) 100%);
color: #ffffff;
font-weight: 500;
font-size: 15px;
letter-spacing: normal;
line-height: 32px;
text-align: center;
border: 2px solid #6aaf5c;
transition: 0.3s;
}
}

View File

@ -20,7 +20,29 @@
border-radius: 8px; border-radius: 8px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
max-height: 750px; max-height: 650px;
overflow-y: auto;
@media (max-width: 880px) {
max-height: none;
overflow-y: inherit;
}
&::-webkit-scrollbar {
width: 3px;
border-radius: 10px;
}
&::-webkit-scrollbar-thumb {
background: #cbd9f9;
border-radius: 20px;
}
&::-webkit-scrollbar-track {
background: #c5c0c6;
border-radius: 20px;
}
.content { .content {
position: relative; position: relative;
@ -125,27 +147,6 @@
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
.taskDescription {
max-height: 150px;
overflow-y: auto;
padding-right: 10px;
&::-webkit-scrollbar {
width: 4px;
border-radius: 10px;
}
&::-webkit-scrollbar-thumb {
background: #cbd9f9;
border-radius: 10px;
}
&::-webkit-scrollbar-track {
background: #c5c0c6;
border-radius: 10px;
}
}
.fullName { .fullName {
max-width: 800px; max-width: 800px;
} }
@ -157,8 +158,6 @@
.comments__list { .comments__list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
max-height: 215px;
overflow: auto;
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 4px; width: 4px;

View File

@ -729,9 +729,12 @@ export const TicketFullScreen = () => {
</div> </div>
)} )}
</div> </div>
<Link to={`/profile/tracker`} className="link"> <Link
to={`/tracker/project/${taskInfo.project_id}`}
className="link"
>
<div className="tasks__head__back"> <div className="tasks__head__back">
<p>Вернуться на проекты</p> <p>Вернуться на проект</p>
<img src={arrow} alt="arrow" /> <img src={arrow} alt="arrow" />
</div> </div>
</Link> </Link>

View File

@ -498,7 +498,7 @@
font-weight: 300; font-weight: 300;
line-height: 18px; line-height: 18px;
font-size: 15px; font-size: 15px;
margin-bottom: 17.5px; margin-bottom: 27px;
z-index: 100; z-index: 100;
} }