diff --git a/zubhub_frontend/zubhub/public/locales/en/translation.json b/zubhub_frontend/zubhub/public/locales/en/translation.json index b03782abe..42d4603e1 100644 --- a/zubhub_frontend/zubhub/public/locales/en/translation.json +++ b/zubhub_frontend/zubhub/public/locales/en/translation.json @@ -724,6 +724,11 @@ "required": "Seems like you forgot this" } }, + "changePassword": { + "newPassword": "Change Password", + "confirmNewPassword": "Retype new password", + "error": "<1/> {{errorMessage}}" + }, "submit": "Save Changes" }, "or": "OR", diff --git a/zubhub_frontend/zubhub/src/assets/js/styles/views/edit_profile/editProfileStyles.js b/zubhub_frontend/zubhub/src/assets/js/styles/views/edit_profile/editProfileStyles.js index 37807e3a9..d677d91de 100644 --- a/zubhub_frontend/zubhub/src/assets/js/styles/views/edit_profile/editProfileStyles.js +++ b/zubhub_frontend/zubhub/src/assets/js/styles/views/edit_profile/editProfileStyles.js @@ -113,6 +113,11 @@ const styles = theme => ({ color: 'var(--primary-color2)', }, fieldHelperTextStyle: { + '&.MuiFormHelperText-root.Mui-error': { + display: 'inline-flex', + alignItems: 'center', + gap: '4px' + }, [theme.breakpoints.up('1600')]: { fontSize: '1.2rem', }, diff --git a/zubhub_frontend/zubhub/src/views/edit_profile/EditProfile.jsx b/zubhub_frontend/zubhub/src/views/edit_profile/EditProfile.jsx index 9f841ddc1..fa143053b 100644 --- a/zubhub_frontend/zubhub/src/views/edit_profile/EditProfile.jsx +++ b/zubhub_frontend/zubhub/src/views/edit_profile/EditProfile.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { Trans } from 'react-i18next' import { Link } from 'react-router-dom'; import clsx from 'clsx'; import PropTypes from 'prop-types'; @@ -14,6 +15,7 @@ import { makeStyles } from '@material-ui/core/styles'; import Visibility from '@material-ui/icons/Visibility'; import VisibilityOff from '@material-ui/icons/VisibilityOff'; +import ErrorIcon from '@material-ui/icons/Error'; import { Grid, @@ -41,6 +43,7 @@ import { } from '@material-ui/core'; import { + customValidation, validationSchema, getLocations, getProfile, @@ -82,7 +85,9 @@ function EditProfile(props) { tool_tip_open: false, dialog_error: null, open_delete_account_modal: false, - show_password: false, + show_current_password: false, + show_new_password: false, + show_confirm_new_password: false, show_delete_account_password: false, }); @@ -92,7 +97,7 @@ function EditProfile(props) { }, []); const classes = useStyles(); - const { show_password, show_delete_account_password } = state; + const { show_current_password, show_new_password, show_confirm_new_password, show_delete_account_password } = state; const handleSetState = obj => { if (obj) { @@ -117,7 +122,7 @@ function EditProfile(props) { className="auth-form" name="signup" noValidate="noValidate" - onSubmit={e => editProfile(e, props, toast)} + onSubmit={props.handleSubmit} > - - - + + - {t('editProfile.inputs.password.label')} - - - - handleSetState(handleClickShowPassword(state)) - } - onMouseDown={handleMouseDownPassword} - edge="end" - > - {show_password ? ( - - ) : ( - + + {t('editProfile.inputs.password.label')} + + + + handleSetState(handleClickShowPassword(state, 'show_current_password')) + } + onMouseDown={handleMouseDownPassword} + edge="end" + > + {show_current_password ? ( + + ) : ( + + )} + + + } + label={t('editProfile.inputs.password.label')} + /> + + {(props.status && props.status['password']) || + (props.errors['password'] && + + {{errorMessage: props.errors['password']}} + + )} + + + + + + + + {t('editProfile.inputs.changePassword.newPassword')} + + + + handleSetState(handleClickShowPassword(state, 'show_new_password')) + } + onMouseDown={handleMouseDownPassword} + edge="end" + > + {show_new_password ? ( + + ) : ( + + )} + + + } + label={t('editProfile.inputs.changePassword.newPassword')} + /> + + {(props.status && props.status['new-password']) || + (props.errors['newPassword'] && + + {{errorMessage: props.errors['newPassword']}} + )} - - + + + + + + - - {(props.status && props.status['password']) || - (props.touched['password'] && - props.errors['password'] && - t( - `editProfile.inputs.password.errors.${props.errors['password']}`, - ))} - - + + {t('editProfile.inputs.changePassword.confirmNewPassword')} + + + + handleSetState(handleClickShowPassword(state, 'show_confirm_new_password')) + } + onMouseDown={handleMouseDownPassword} + edge="end" + > + { show_confirm_new_password ? ( + + ) : ( + + )} + + + } + label={t('editProfile.inputs.changePassword.confirmNewPassword')} + /> + + {(props.status && props.status['confirmNewPassword']) || + (props.touched['confirmNewPassword'] && + props.errors['confirmNewPassword'] && + ( + + {{errorMessage: props.errors['confirmNewPassword']}} + + ) + )} + + + @@ -708,9 +836,15 @@ export default connect( email: '', phone: '', password: '', + newPassword: '', + confirmNewPassword: '', user_location: '', bio: '', }), validationSchema, + handleSubmit: (values, { props }) => { + return editProfile(values, props, toast) + }, + validate: customValidation })(EditProfile), ); diff --git a/zubhub_frontend/zubhub/src/views/edit_profile/editProfileScripts.js b/zubhub_frontend/zubhub/src/views/edit_profile/editProfileScripts.js index 44906eff0..5703561b4 100644 --- a/zubhub_frontend/zubhub/src/views/edit_profile/editProfileScripts.js +++ b/zubhub_frontend/zubhub/src/views/edit_profile/editProfileScripts.js @@ -16,9 +16,12 @@ export const getLocations = props => { * * @todo - describe function's signature */ -export const handleClickShowPassword = state => { - const { show_password } = state; - return { show_password: !show_password }; +export const handleClickShowPassword = (state, value) => { + const currentValue = state[value] + return { + ...state, + [value]: !currentValue + } }; /** @@ -135,20 +138,12 @@ export const deleteAccount = (username_el, props, toast) => { * * @todo - describe function's signature */ -export const editProfile = (e, props, toast) => { - e.preventDefault(); - props.setFieldTouched('username', true); - props.setFieldTouched('email', true); - props.setFieldTouched('phone', true); - props.setFieldTouched('password', true); - props.setFieldTouched('user_location', true); +export const editProfile = (values, props, toast) => { let password_match = true; - if (props.values.user_location.length < 1) { - props.validateField('user_location'); - } else if (props.values.password.length < 1) { - props.validateField('password'); - } else { - props.login({ values: props.values, history: props.history }).catch(error => { + + if (values.password) { + props.validateField('password') + props.login({ values: values, history: props.history }).catch(error => { try{ const messages = JSON.parse(error.message); toast.error(props.t('editProfile.inputs.password.errors.invalid')); @@ -162,7 +157,7 @@ export const editProfile = (e, props, toast) => { return; } else { return props - .editUserProfile({ ...props.values, token: props.auth.token }) + .editUserProfile({ ...values, token: props.auth.token }) .then(_ => { toast.success(props.t('editProfile.toastSuccess')); props.history.push('/profile'); @@ -221,7 +216,15 @@ export const handleTooltipClose = () => { export const validationSchema = Yup.object().shape({ username: Yup.string().required('required'), user_location: Yup.string().min(1, 'min').required('required'), - password: Yup.string().required('required'), + password: Yup.string().required('Your password is required'), + newPassword: Yup.string() + .oneOf([Yup.ref('confirmNewPassword'), null], 'Passwords must match'), + confirmNewPassword: Yup.string() + .when('newPassword', { + is: (newPassword) => newPassword && newPassword.length > 0, + then: Yup.string().oneOf([Yup.ref('newPassword')], 'Passwords must match').required('Retype new password'), + otherwise: Yup.string().notRequired(), + }), email: Yup.string().email('invalid').when('phone', { is: (phone) => !phone || phone.length === 0, then: Yup.string().required('phoneOrEmail') @@ -233,4 +236,16 @@ export const validationSchema = Yup.object().shape({ return /^[+][0-9]{9,15}$/g.test(value) || !value ? true : false; }), bio: Yup.string().max(255, 'tooLong'), -}, ['phone', 'email']); \ No newline at end of file +}, ['phone', 'email']); + + + + export function customValidation(values, props) { + const errors = {}; + if (values.confirmNewPassword && !values.newPassword) { + errors.newPassword = 'You have to input here first'; + } + + return errors; + +} \ No newline at end of file