Skip to content

Commit

Permalink
Create page for reset password
Browse files Browse the repository at this point in the history
  • Loading branch information
whooaami committed Oct 28, 2023
1 parent 32bb0a9 commit 6c873eb
Show file tree
Hide file tree
Showing 11 changed files with 880 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import styles from './RestorePasswordForm.module.css';
import { RestorePasswordFormContentComponent } from './restorepassword-form/RestorePasswordFormContent';
import { useState } from 'react';
import { Link } from 'react-router-dom';


export function RestorePasswordFormComponent() {
const [isValid, setIsValid] = useState(false);
const updateIsValid = (value) => {
setIsValid(value);
};
return (
<div className={styles['form__container']}>
<div className={styles['form__header']}>Відновлення паролю</div>
<RestorePasswordFormContentComponent setIsValid={updateIsValid}/>
<div className={styles['form__footer']}>
<div className={styles['button-container']}>
<Link className={styles['main-page__button']} to="/">
Головна
</Link>
<button
disabled={!isValid}
form="resetPasswordForm"
className={isValid ? styles['sign-up__button'] : styles['sign-up__button__disabled']}
type="submit"
>
Зберегти
</button>
</div>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
.form__container {
display: flex;
width: 572px;
flex-direction: column;
align-items: flex-start;

border-radius: 2px;
background: var(--conditional-pop-over, #fff);

/* drop-shadow/0.12+0.8+0.5 */
box-shadow: 0px 9px 28px 8px rgba(0, 0, 0, 0.05),
0px 6px 16px 0px rgba(0, 0, 0, 0.08), 0px 3px 6px -4px rgba(0, 0, 0, 0.12);
}

.form__header {
display: flex;
padding: 16px 24px;
align-items: flex-start;
gap: 36px;
align-self: stretch;
background: var(--main-white, #fff);

/* border & divider/divider ↓ */
box-shadow: 0px -1px 0px 0px #f0f0f0 inset;
color: var(--character-title-85, rgba(0, 0, 0, 0.85));
font-feature-settings: "calt" off;

/* Text/Body/16-Semi bold */
font-family: Inter, sans-serif;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 20px;
/* 125% */
letter-spacing: -0.16px;
}

.form__footer {
display: flex;
padding: 10px 16px;
justify-content: flex-end;
align-items: center;
gap: 8px;
align-self: stretch;
background: var(--main-white, #fff);

/* border & divider/divider ↑ */
box-shadow: 0px 1px 0px 0px #f0f0f0 inset;
}

.button-container {
display: flex;
align-items: flex-start;
gap: 12px;
}

.main-page__button {
display: flex;
padding: 5px 15px;
justify-content: center;
align-items: center;
gap: 10px;
border-radius: 4px;
border: 1px solid var(--primary-green-80, #1f9a7c);
background: var(--main-white, #fff);

/* drop-shadow/button-secondary */
box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, 0.02);

color: var(--primary-green-80, #1f9a7c);
text-align: center;
font-feature-settings: "calt" off;

/* Text/Body/16-Semi bold */
font-family: Inter, sans-serif;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 20px;
/* 125% */
letter-spacing: -0.16px;
text-decoration: none;

cursor: pointer;
}

.main-page__button:hover {
border: 1px solid var(--primary-green-80, #1f9a7c);
background: var(--primary-green-80, #1f9a7c);
color: var(--main-white, #fff);
}

.sign-up__button,
.sign-up__button__disabled {
display: flex;
padding: 5px 15px;
justify-content: center;
align-items: center;
gap: 10px;
border-radius: 4px;
border: 1px solid var(--primary-green-80, #1f9a7c);
background: var(--primary-green-80, #1f9a7c);

/* drop-shadow/button-primary */
box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, 0.04);
color: var(--main-white, #fff);
text-align: center;
font-feature-settings: "calt" off;

/* Text/Body/16-Semi bold */
font-family: Inter, sans-serif;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 20px;
/* 125% */
letter-spacing: -0.16px;

cursor: pointer;
}

.sign-up__button__disabled {
opacity: 50%;
cursor: default;
}

.sign-up__button:hover {
border: 1px solid var(--primary-green-80, #1f9a7c);
background: var(--main-white, #fff);
color: var(--primary-green-80, #1f9a7c);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { useParams } from 'react-router-dom';
import EyeInvisible from '../../../../authorization/EyeInvisible';
import EyeVisible from '../../../../authorization/EyeVisible';
import styles from './RestorePasswordFormContent.module.css';

export function RestorePasswordFormContentComponent({ setIsValid }) {
const navigate = useNavigate();
const { uid, token } = useParams();
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);

const togglePassword = () => {
setShowPassword(!showPassword);
};

const toggleConfirmPassword = () => {
setShowConfirmPassword(!showConfirmPassword);
};

const errorMessageTemplates = {
required: 'Обов’язкове поле',
password: 'Пароль не відповідає вимогам',
confirmPassword: 'Паролі не збігаються',
};

const passwordPattern = /^(?=.*[0-9])(?=.*[a-zA-Z])[a-zA-Z0-9]{8,20}$/;

const {
register,
handleSubmit,
getValues,
formState: { errors, isValid },
} = useForm();

useEffect(() => {
const formIsValid = isValid;
setIsValid(formIsValid);
}, [isValid, setIsValid]);

const onSubmit = (formData) => {
const dataToSend = {
uid: uid,
token: token,
new_password: formData.new_password,
re_new_password: formData.confirmPassword,
};

axios
.post(
`${process.env.REACT_APP_BASE_API_URL}/api/auth/users/reset_password_confirm/`,
dataToSend
)
.then(() => {
setIsValid(true);
navigate('/login');
})
.catch((error) => {
console.log(error);
});
};

return (
<div>

<div className={styles['signup-form']}>
<form
id="resetPasswordForm"
className={styles['signup-form__container']}
onSubmit={handleSubmit(onSubmit)}
autoComplete="off"
noValidate
>
<div className={styles['signup-form__column']}>
<div className={styles['signup-form__column']}>
<div className={styles['signup-form__label']}>
<label className={styles['signup-form__label--required']}>*</label>
<div className={styles['signup-form__label--password']}>
<label>Новий пароль</label>
<label className={styles['signup-form__label--hint']}>
(Повинен містити A-Z, a-z, 0-9)
</label>
</div>
</div>
<div className={styles['signup-form__field__password']}>
<input
className={styles['signup-form__input__password']}
placeholder="Новий пароль"
type={showPassword ? 'text' : 'password'}
{...register('new_password', {
required: errorMessageTemplates.required,
pattern: {
value: passwordPattern,
message: errorMessageTemplates.password,
},
})}
/>
<span
className={styles['password-visibility']}
onClick={togglePassword}
>
{!showPassword ? <EyeInvisible /> : <EyeVisible />}
</span>
</div>
<div className={styles['signup-form__error']}>
{errors.new_password && errors.new_password.message}
</div>
</div>
<div className={styles['signup-form__column']}>
<div className={styles['signup-form__label']}>
<label className={styles['signup-form__label--required']}>*</label>
<div className={styles['signup-form__label--password']}>
<label className={styles['signup-form__label--text']}>
Повторіть пароль
</label>
</div>
</div>
<div className={styles['signup-form__field__password']}>
<input
className={styles['signup-form__input__password']}
placeholder="Повторіть пароль"
type={showConfirmPassword ? 'text' : 'password'}
{...register('confirmPassword', {
required: errorMessageTemplates.required,
validate: (value) =>
value === getValues('new_password') ||
errorMessageTemplates.confirmPassword,
})}
/>
<span
className={styles['password-visibility']}
onClick={toggleConfirmPassword}
>
{!showConfirmPassword ? <EyeInvisible /> : <EyeVisible />}
</span>
</div>
<div className={styles['signup-form__error']}>
{errors.confirmPassword && errors.confirmPassword.message}
</div>
</div>
</div>
</form>
</div>
</div>
);
}
Loading

0 comments on commit 6c873eb

Please sign in to comment.