diff --git a/FrontEnd/src/components/ProfilePage/FormComponents/ChangePassword.js b/FrontEnd/src/components/ProfilePage/FormComponents/ChangePassword.js
new file mode 100644
index 000000000..8c7c99590
--- /dev/null
+++ b/FrontEnd/src/components/ProfilePage/FormComponents/ChangePassword.js
@@ -0,0 +1,125 @@
+import axios from 'axios';
+import { PropTypes } from 'prop-types';
+import { toast } from 'react-toastify';
+import { useEffect } from 'react';
+import { useContext } from 'react';
+import { useForm } from 'react-hook-form';
+import { DirtyFormContext } from '../../../context/DirtyFormContext';
+import PasswordField from './FormFields/PasswordField';
+import Loader from '../../loader/Loader';
+import css from './ChangePassword.module.css';
+
+
+export default function ChangePassword(props) {
+ const { setFormIsDirty } = useContext(DirtyFormContext);
+ const { currentFormNameHandler, curForm } = props;
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ reset,
+ formState: { errors, isDirty },
+ } = useForm({
+ mode: 'all',
+ defaultValues: {
+ currentPassword: '',
+ newPassword: '',
+ reNewPassword: ''
+ }
+ });
+
+ useEffect(() => {
+ currentFormNameHandler(curForm);
+ }, [currentFormNameHandler, curForm]);
+
+ useEffect(() => {
+ setFormIsDirty(isDirty);
+ }, [isDirty, setFormIsDirty]
+ );
+
+ const handleFormSubmit = () => {
+ axios.post(`${process.env.REACT_APP_BASE_API_URL}/api/auth/users/set_password/`, {
+ current_password: getValues('currentPassword'),
+ new_password: getValues('newPassword'),
+ re_new_password: getValues('reNewPassword')
+ })
+ .then(() => toast.success('Пароль успішно змінено'))
+ .catch(() => toast.error('Виникла помилка. Можливо, вказано невірний поточний пароль'));
+ reset();
+ };
+
+ return (
+
+ {props.user
+ ?
+
+ :
+ }
+
+ );
+}
+
+ChangePassword.propTypes = {
+ user: PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ email: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+ surname: PropTypes.string.isRequired,
+ profile_id: PropTypes.number.isRequired,
+ is_staff: PropTypes.bool.isRequired
+ }).isRequired,
+ currentFormNameHandler: PropTypes.func.isRequired,
+ curForm: PropTypes.string.isRequired
+};
+
+
diff --git a/FrontEnd/src/components/ProfilePage/FormComponents/ChangePassword.module.css b/FrontEnd/src/components/ProfilePage/FormComponents/ChangePassword.module.css
new file mode 100644
index 000000000..776533af1
--- /dev/null
+++ b/FrontEnd/src/components/ProfilePage/FormComponents/ChangePassword.module.css
@@ -0,0 +1,5 @@
+.form__container {
+ word-wrap: break-word;
+ width: 530px;
+ margin-left: 10px;
+}
\ No newline at end of file
diff --git a/FrontEnd/src/components/ProfilePage/FormComponents/FormFields/PasswordField.js b/FrontEnd/src/components/ProfilePage/FormComponents/FormFields/PasswordField.js
new file mode 100644
index 000000000..e772d4f07
--- /dev/null
+++ b/FrontEnd/src/components/ProfilePage/FormComponents/FormFields/PasswordField.js
@@ -0,0 +1,102 @@
+import { useState } from 'react';
+import { PropTypes } from 'prop-types';
+import EyeInvisible from '../../../authorization/EyeInvisible';
+import EyeVisible from '../../../authorization/EyeVisible';
+import css from './PasswordField.module.css';
+import { PASSWORD_PATTERN } from '../../../../constants/constants';
+
+const PasswordField = (props) => {
+
+ const errorMessages = {
+ invalidPassword: 'Пароль не відповідає вимогам',
+ passwordsDontMatch: 'Паролі не співпадають'
+ };
+
+ const [showPassword, setShowPassword] = useState(false);
+
+ const togglePassword = () => {
+ setShowPassword(!showPassword);
+ };
+
+ const {
+ register,
+ name,
+ error,
+ showError,
+ watch,
+ label,
+ inputId,
+ checkValid,
+ checkMatch
+ } = props;
+
+ return (
+
+
+
+ *
+
+
+
+
+
+ {
+ return value === watch(checkMatch.checkWith) ||
+ value === '' ||
+ errorMessages.passwordsDontMatch;
+ } :
+ null
+ })}
+ />
+
+
+ {!showPassword ? : }
+
+
+ {(error[name] && showError) ?
+
+ {error[name].message}
+
+ :
+ null
+ }
+
+ );
+};
+
+PasswordField.propTypes = {
+ name: PropTypes.string.isRequired,
+ label: PropTypes.string.isRequired,
+ register: PropTypes.func.isRequired,
+ watch: PropTypes.func.isRequired,
+ inputId: PropTypes.string.isRequired,
+ showError: PropTypes.bool.isRequired,
+ error: PropTypes.object,
+ checkValid: PropTypes.bool.isRequired,
+ checkMatch: PropTypes.shape({
+ isCheck: PropTypes.bool.isRequired,
+ checkWith: PropTypes.string
+ })
+};
+
+export default PasswordField;
\ No newline at end of file
diff --git a/FrontEnd/src/components/ProfilePage/FormComponents/FormFields/PasswordField.module.css b/FrontEnd/src/components/ProfilePage/FormComponents/FormFields/PasswordField.module.css
new file mode 100644
index 000000000..0011f4eb6
--- /dev/null
+++ b/FrontEnd/src/components/ProfilePage/FormComponents/FormFields/PasswordField.module.css
@@ -0,0 +1,83 @@
+.password-field__item {
+ display: flex;
+ width: 257px;
+ height: 89px;
+ flex-direction: column;
+ align-items: flex-start;
+}
+
+.password-field__label-wrapper {
+ padding-bottom: 9px;
+}
+
+.password-field__label-wrapper span {
+ padding-right: 5px;
+ color: #FF4D4F;
+}
+
+.password-field__item input {
+ border: none;
+}
+.password-field__item input:focus {
+ border: none;
+ outline: none;
+}
+
+.password-field__item input::placeholder {
+ font-style: normal;
+ font-family: "Inter", sans-serif;
+ font-size: 14px;
+ font-weight: 400;
+ line-height: 22px;
+ letter-spacing: -0.01em;
+ text-align: left;
+ color: #00000040;
+}
+.password-field__password {
+ display: flex;
+ padding: 4px 12px;
+ align-items: center;
+ gap: 4px;
+ align-self: stretch;
+ border-radius: 2px;
+ border: 1px solid #d9d9d9;
+ background: #fff;
+}
+
+.password-field__password:focus {
+ border-radius: 2px;
+ border: 1px solid #1f9a7c;
+ background: #fff;
+ outline: none;
+}
+
+.password-field__password:focus-within {
+ border-radius: 2px;
+ border: 1px solid #1f9a7c;
+ background: #fff;
+ }
+
+.password-field__password__wrapper {
+ display: flex;
+}
+
+.password-visibility {
+ cursor: pointer;
+ margin-left: auto;
+}
+
+.error-message {
+ display: flex;
+ padding: 1px 0px;
+ align-items: flex-start;
+ gap: 10px;
+ align-self: stretch;
+ flex: 1 0 0;
+ color: var(--red-red-100, #F34444);
+ font-family: Roboto;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 22px;
+}
+
diff --git a/FrontEnd/src/components/ProfilePage/ProfilePageComponents/Description.js b/FrontEnd/src/components/ProfilePage/ProfilePageComponents/Description.js
index b14ee13b5..ba2fe0f8f 100644
--- a/FrontEnd/src/components/ProfilePage/ProfilePageComponents/Description.js
+++ b/FrontEnd/src/components/ProfilePage/ProfilePageComponents/Description.js
@@ -9,6 +9,7 @@ const DESCRIPTIONS = {
'AdditionalInfo': 'Інформація про компанію',
'StartupInfo': 'Інформація про стартап',
'Delete': 'Видалення профілю',
+ 'ChangePassword': 'Зміна паролю користувача'
};
const Description = (props) => {
diff --git a/FrontEnd/src/components/ProfilePage/ProfilePageComponents/ProfileContent.js b/FrontEnd/src/components/ProfilePage/ProfilePageComponents/ProfileContent.js
index 25b60c6dc..4e5f6631a 100644
--- a/FrontEnd/src/components/ProfilePage/ProfilePageComponents/ProfileContent.js
+++ b/FrontEnd/src/components/ProfilePage/ProfilePageComponents/ProfileContent.js
@@ -13,6 +13,7 @@ import UserInfo from '../FormComponents/UserInfo';
import ProfileFormButton from '../UI/ProfileFormButton/ProfileFormButton';
import MyModal from '../UI/MyModal/MyModal';
import WarnUnsavedDataModal from '../FormComponents/WarnUnsavedDataModal';
+import ChangePassword from '../FormComponents/ChangePassword';
import css from './ProfileContent.module.css';
@@ -53,7 +54,8 @@ const FORM_NAMES = [
'ProductServiceInfo',
'AdditionalInfo',
'StartupInfo',
- 'Delete'
+ 'Delete',
+ 'ChangePassword'
];
const ProfileContent = (props) => {
@@ -143,6 +145,11 @@ const ProfileContent = (props) => {
);
})}
+
+ Змінити пароль
+
@@ -191,6 +198,12 @@ const ProfileContent = (props) => {
profile={props.profile}
currentFormNameHandler={props.currentFormNameHandler}
curForm={FORM_NAMES[5]} />} />
+ } />