diff --git a/frontend/app/components/Client/ProfileSettings/ChangePassword.js b/frontend/app/components/Client/ProfileSettings/ChangePassword.js
deleted file mode 100644
index 2640ab612..000000000
--- a/frontend/app/components/Client/ProfileSettings/ChangePassword.js
+++ /dev/null
@@ -1,121 +0,0 @@
-import React from 'react';
-import { connect } from 'react-redux';
-import { Button, Message, Form, Input } from 'UI';
-import styles from './profileSettings.module.css';
-import { updatePassword } from 'Duck/user';
-import { toast } from 'react-toastify';
-
-const ERROR_DOESNT_MATCH = "Passwords doesn't match";
-const MIN_LENGTH = 8;
-const PASSWORD_POLICY = `Password should contain at least ${MIN_LENGTH} symbols`;
-const checkDoesntMatch = (newPassword, newPasswordRepeat) => newPasswordRepeat.length > 0 && newPasswordRepeat !== newPassword;
-
-const defaultState = {
- oldPassword: '',
- newPassword: '',
- newPasswordRepeat: '',
- success: false,
- show: false,
-};
-@connect(
- (state) => ({
- passwordErrors: state.getIn(['user', 'passwordErrors']),
- loading: state.getIn(['user', 'updatePasswordRequest', 'loading']),
- }),
- {
- updatePassword,
- }
-)
-export default class ChangePassword extends React.PureComponent {
- state = defaultState;
-
- write = ({ target: { name, value } }) => {
- this.setState({
- [name]: value,
- });
- };
-
- handleSubmit = (e) => {
- e.preventDefault();
- if (this.isSubmitDisabled()) return;
-
- const { oldPassword, newPassword } = this.state;
- this.setState({
- success: false,
- });
-
- this.props
- .updatePassword({
- oldPassword,
- newPassword,
- })
- .then((e) => {
- const success = !e || !e.errors || e.errors.length === 0;
- this.setState({
- ...defaultState,
- success: success,
- show: !success
- });
- if (success) {
- toast.success(`Successfully changed password`);
- }
- });
- };
-
- isSubmitDisabled() {
- const { oldPassword, newPassword, newPasswordRepeat } = this.state;
- if (newPassword !== newPasswordRepeat || newPassword.length < MIN_LENGTH || oldPassword.length < MIN_LENGTH) return true;
- return false;
- }
-
- render() {
- const { oldPassword, newPassword, newPasswordRepeat, success, show } = this.state;
- const { loading, passwordErrors } = this.props;
-
- const doesntMatch = checkDoesntMatch(newPassword, newPasswordRepeat);
- return show ? (
-
-
-
-
-
-
-
- {PASSWORD_POLICY}
-
-
-
-
-
- {passwordErrors.map((err) => (
- {err}
- ))}
-
- {ERROR_DOESNT_MATCH}
-
-
-
-
-
-
-
- ) : (
- this.setState({ show: true })}>
-
-
- );
- }
-}
diff --git a/frontend/app/components/Client/ProfileSettings/ChangePassword.tsx b/frontend/app/components/Client/ProfileSettings/ChangePassword.tsx
new file mode 100644
index 000000000..c299cc5b1
--- /dev/null
+++ b/frontend/app/components/Client/ProfileSettings/ChangePassword.tsx
@@ -0,0 +1,171 @@
+import React, { useState, useCallback } from 'react';
+import { connect, ConnectedProps } from 'react-redux';
+import { Button, Message, Form, Input } from 'UI';
+import styles from './profileSettings.module.css';
+import { updatePassword } from 'Duck/user';
+import { toast } from 'react-toastify';
+
+const ERROR_DOESNT_MATCH = "Passwords don't match";
+const MIN_LENGTH = 8;
+const PASSWORD_POLICY = `Password should contain at least ${MIN_LENGTH} symbols`;
+
+type PropsFromRedux = ConnectedProps;
+
+const ChangePassword: React.FC = ({ passwordErrors, loading, updatePassword }) => {
+ const [oldPassword, setOldPassword] = useState('');
+ const [newPassword, setNewPassword] = useState<{ value: string; error: boolean }>({
+ value: '',
+ error: false,
+ });
+ const [newPasswordRepeat, setNewPasswordRepeat] = useState<{ value: string; error: boolean }>({
+ value: '',
+ error: false,
+ });
+ const [success, setSuccess] = useState(false);
+ const [show, setShow] = useState(false);
+
+ const checkDoesntMatch = useCallback((newPassword: string, newPasswordRepeat: string) => {
+ return newPasswordRepeat.length > 0 && newPasswordRepeat !== newPassword;
+ }, []);
+
+ const isSubmitDisabled = useCallback(() => {
+ if (
+ newPassword.value !== newPasswordRepeat.value ||
+ newPassword.value.length < MIN_LENGTH ||
+ oldPassword.length === 0
+ ) {
+ return true;
+ }
+ return false;
+ }, [newPassword, newPasswordRepeat, oldPassword]);
+
+ const validatePassword = (password: string) => {
+ const regex =
+ /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?])[A-Za-z\d!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]{8,}$/;
+ return regex.test(password);
+ };
+
+ const handleSubmit = useCallback(
+ (e: React.FormEvent) => {
+ e.preventDefault();
+ if (isSubmitDisabled()) return;
+
+ if (!validatePassword(newPassword.value)) {
+ setNewPassword({ ...newPassword, error: true });
+ return;
+ }
+
+ updatePassword({
+ oldPassword,
+ newPassword: newPassword.value,
+ }).then((e: any) => {
+ const success = !e || !e.errors || e.errors.length === 0;
+ setSuccess(success);
+ setShow(!success);
+ if (success) {
+ toast.success(`Successfully changed password`);
+ setOldPassword('');
+ setNewPassword({ value: '', error: false });
+ setNewPasswordRepeat({ value: '', error: false });
+ }
+ });
+ },
+ [isSubmitDisabled, oldPassword, newPassword, updatePassword]
+ );
+
+ return show ? (
+
+
+ ) => setOldPassword(e.target.value)}
+ />
+
+
+
+ ) => {
+ const newValue = e.target.value;
+ const isValid = validatePassword(newValue);
+ setNewPassword({ value: newValue, error: !isValid });
+ }}
+ />
+
+
+
+ ) => {
+ const newValue = e.target.value;
+ const isValid = newValue === newPassword.value;
+ setNewPasswordRepeat({ value: newValue, error: !isValid });
+ }}
+ />
+
+ {passwordErrors.map((err, i) => (
+
+ {err}
+
+ ))}
+
+ {ERROR_DOESNT_MATCH}
+
+
+ Password should contain at least one capital letter, special character, and digit, and
+ length min 8
+
+ {/*
+ Passwords don't match
+ */}
+
+
+
+
+
+ ) : (
+ setShow(true)}>
+
+
+ );
+};
+
+const mapStateToProps = (state: any) => ({
+ passwordErrors: state.getIn(['user', 'passwordErrors']),
+ loading: state.getIn(['user', 'updatePasswordRequest', 'loading']),
+});
+
+const mapDispatchToProps = {
+ updatePassword,
+};
+
+const connector = connect(mapStateToProps, mapDispatchToProps);
+
+export default connector(ChangePassword);