mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-09 15:54:47 -07:00
connect reset password to login view (#4489)
This commit is contained in:
parent
811ee54c76
commit
1f15445c69
31 changed files with 893 additions and 445 deletions
|
|
@ -10,9 +10,29 @@ import { InputField } from 'components';
|
|||
|
||||
import './KnownHostForm.css';
|
||||
|
||||
function KnownHostForm({ host, onRemove, onSubmit }) {
|
||||
const KnownHostForm = ({ host, onRemove, onSubmit }) => {
|
||||
const [confirmDelete, setConfirmDelete] = useState(false);
|
||||
|
||||
const validate = values => {
|
||||
const errors: any = {};
|
||||
|
||||
if (!values.name) {
|
||||
errors.name = 'Required'
|
||||
}
|
||||
|
||||
if (!values.host) {
|
||||
errors.host = 'Required'
|
||||
}
|
||||
|
||||
if (!values.port) {
|
||||
errors.port = 'Required'
|
||||
}
|
||||
|
||||
if (Object.keys(errors).length) {
|
||||
return errors;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
initialValues={{
|
||||
|
|
@ -22,25 +42,7 @@ function KnownHostForm({ host, onRemove, onSubmit }) {
|
|||
port: host?.port,
|
||||
}}
|
||||
onSubmit={onSubmit}
|
||||
validate={values => {
|
||||
const errors: any = {};
|
||||
|
||||
if (!values.name) {
|
||||
errors.name = 'Required'
|
||||
}
|
||||
|
||||
if (!values.host) {
|
||||
errors.host = 'Required'
|
||||
}
|
||||
|
||||
if (!values.port) {
|
||||
errors.port = 'Required'
|
||||
}
|
||||
|
||||
if (Object.keys(errors).length) {
|
||||
return errors;
|
||||
}
|
||||
}}
|
||||
validate={validate}
|
||||
>
|
||||
{({ handleSubmit }) => (
|
||||
<form className="KnownHostForm" onSubmit={handleSubmit}>
|
||||
|
|
@ -74,7 +76,7 @@ function KnownHostForm({ host, onRemove, onSubmit }) {
|
|||
) }
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const mapStateToProps = () => ({
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// eslint-disable-next-line
|
||||
import React, { Component, useCallback, useEffect, useState, useRef } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Form, Field, reduxForm, change, FormSubmitHandler } from 'redux-form'
|
||||
import { Form, Field, useField } from 'react-final-form';
|
||||
import { OnChange } from 'react-final-form-listeners';
|
||||
|
||||
import Button from '@material-ui/core/Button';
|
||||
|
||||
|
|
@ -16,151 +17,142 @@ import './LoginForm.css';
|
|||
const PASSWORD_LABEL = 'Password';
|
||||
const STORED_PASSWORD_LABEL = '* SAVED *';
|
||||
|
||||
const LoginForm: any = ({ dispatch, form, submit, handleSubmit }: LoginFormProps) => {
|
||||
const password: any = useRef();
|
||||
const LoginForm = ({ onSubmit, onResetPassword }: LoginFormProps) => {
|
||||
const [host, setHost] = useState(null);
|
||||
const [remember, setRemember] = useState(false);
|
||||
const [passwordLabel, setPasswordLabel] = useState(PASSWORD_LABEL);
|
||||
const [hasStoredPassword, useStoredPassword] = useState(false);
|
||||
const [autoConnect, setAutoConnect] = useAutoConnect();
|
||||
|
||||
const [autoConnect, setAutoConnect] = useAutoConnect(() => {
|
||||
dispatch(change(form, 'autoConnect', autoConnect));
|
||||
|
||||
if (autoConnect && !remember) {
|
||||
setRemember(true);
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
SettingDTO.get(APP_USER).then((userSetting: SettingDTO) => {
|
||||
if (userSetting?.autoConnect && !AuthenticationService.connectionAttemptMade()) {
|
||||
HostDTO.getAll().then(hosts => {
|
||||
let lastSelectedHost = hosts.find(({ lastSelected }) => lastSelected);
|
||||
|
||||
if (lastSelectedHost?.remember && lastSelectedHost?.hashedPassword) {
|
||||
dispatch(change(form, 'selectedHost', lastSelectedHost));
|
||||
dispatch(change(form, 'userName', lastSelectedHost.userName));
|
||||
dispatch(change(form, 'remember', true));
|
||||
setPasswordLabel(STORED_PASSWORD_LABEL);
|
||||
dispatch(submit);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [submit, dispatch, form]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(change(form, 'remember', remember));
|
||||
|
||||
if (!remember) {
|
||||
setAutoConnect(false);
|
||||
}
|
||||
|
||||
if (!remember) {
|
||||
useStoredPassword(false);
|
||||
setPasswordLabel(PASSWORD_LABEL);
|
||||
} else if (host?.hashedPassword) {
|
||||
useStoredPassword(true);
|
||||
setPasswordLabel(STORED_PASSWORD_LABEL);
|
||||
}
|
||||
}, [remember, dispatch, form]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!host) {
|
||||
return
|
||||
}
|
||||
|
||||
dispatch(change(form, 'userName', host.userName));
|
||||
dispatch(change(form, 'password', ''));
|
||||
|
||||
setRemember(host.remember);
|
||||
setAutoConnect(host.remember && autoConnect);
|
||||
|
||||
if (host.remember && host.hashedPassword) {
|
||||
// TODO: check if this causes a double render (maybe try combined state)
|
||||
// try deriving useStoredPassword
|
||||
useStoredPassword(true);
|
||||
setPasswordLabel(STORED_PASSWORD_LABEL);
|
||||
} else {
|
||||
useStoredPassword(false);
|
||||
setPasswordLabel(PASSWORD_LABEL);
|
||||
}
|
||||
}, [host, dispatch, form]);
|
||||
|
||||
const onRememberChange = event => setRemember(event.target.checked);
|
||||
const onAutoConnectChange = event => setAutoConnect(event.target.checked);
|
||||
const onHostChange = h => setHost(h);
|
||||
|
||||
const forgotPassword = () => {
|
||||
console.log('Show recover password dialog, then AuthService.forgotPasswordRequest');
|
||||
};
|
||||
|
||||
return (
|
||||
<Form className='loginForm' onSubmit={handleSubmit}>
|
||||
<div className='loginForm-items'>
|
||||
<div className='loginForm-item'>
|
||||
<Field label='Username' name='userName' component={InputField} autoComplete='off' />
|
||||
</div>
|
||||
<div className='loginForm-item'>
|
||||
<Field
|
||||
label={passwordLabel}
|
||||
ref={password}
|
||||
onFocus={() => setPasswordLabel(PASSWORD_LABEL)}
|
||||
onBlur={() => !password.current.value && hasStoredPassword && setPasswordLabel(STORED_PASSWORD_LABEL)}
|
||||
name='password'
|
||||
type='password'
|
||||
component={InputField}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</div>
|
||||
<div className='loginForm-actions'>
|
||||
<Field label='Save Password' name='remember' component={CheckboxField} onChange={onRememberChange} />
|
||||
<Button color='primary' onClick={forgotPassword}>Forgot Password</Button>
|
||||
</div>
|
||||
<div className='loginForm-item'>
|
||||
<Field name='selectedHost' component={KnownHosts} onChange={onHostChange} />
|
||||
</div>
|
||||
<div className='loginForm-actions'>
|
||||
<Field label='Auto Connect' name='autoConnect' component={CheckboxField} onChange={onAutoConnectChange} />
|
||||
</div>
|
||||
</div>
|
||||
<Button className='loginForm-submit rounded tall' color='primary' variant='contained' type='submit'>
|
||||
Login
|
||||
</Button>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
const propsMap = {
|
||||
form: FormKey.LOGIN,
|
||||
validate: values => {
|
||||
const validate = values => {
|
||||
const errors: any = {};
|
||||
|
||||
if (!values.user) {
|
||||
errors.user = 'Required';
|
||||
if (!values.userName) {
|
||||
errors.userName = 'Required';
|
||||
}
|
||||
|
||||
if (!values.password && !values.selectedHost?.hashedPassword) {
|
||||
errors.password = 'Required';
|
||||
}
|
||||
|
||||
if (!values.selectedHost) {
|
||||
errors.selectedHost = 'Required';
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
const useStoredPassword = (remember) => remember && host.hashedPassword;
|
||||
const togglePasswordLabel = (useStoredLabel) => {
|
||||
setPasswordLabel(useStoredLabel ? STORED_PASSWORD_LABEL : PASSWORD_LABEL);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form onSubmit={onSubmit} validate={validate}>
|
||||
{({ handleSubmit, form }) => {
|
||||
const { values } = form.getState();
|
||||
|
||||
useEffect(() => {
|
||||
SettingDTO.get(APP_USER).then((userSetting: SettingDTO) => {
|
||||
if (userSetting?.autoConnect && !AuthenticationService.connectionAttemptMade()) {
|
||||
HostDTO.getAll().then(hosts => {
|
||||
let lastSelectedHost = hosts.find(({ lastSelected }) => lastSelected);
|
||||
|
||||
if (lastSelectedHost?.remember && lastSelectedHost?.hashedPassword) {
|
||||
togglePasswordLabel(true);
|
||||
|
||||
form.change('selectedHost', lastSelectedHost);
|
||||
form.change('userName', lastSelectedHost.userName);
|
||||
form.change('remember', true);
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!host) {
|
||||
return;
|
||||
}
|
||||
|
||||
form.change('userName', host.userName);
|
||||
form.change('password', '');
|
||||
|
||||
onRememberChange(host.remember);
|
||||
onAutoConnectChange(host.remember && autoConnect);
|
||||
togglePasswordLabel(useStoredPassword(host.remember));
|
||||
}, [host]);
|
||||
|
||||
const onUserNameChange = (userName) => {
|
||||
const fieldChanged = host.userName?.toLowerCase() !== values.userName?.toLowerCase();
|
||||
if (useStoredPassword(values.remember) && fieldChanged) {
|
||||
setHost(({ hashedPassword, ...s }) => ({ ...s, userName }));
|
||||
}
|
||||
}
|
||||
|
||||
const onRememberChange = (checked) => {
|
||||
form.change('remember', checked);
|
||||
|
||||
if (!checked && values.autoConnect) {
|
||||
onAutoConnectChange(false);
|
||||
}
|
||||
|
||||
togglePasswordLabel(useStoredPassword(checked));
|
||||
}
|
||||
|
||||
const onAutoConnectChange = (checked) => {
|
||||
setAutoConnect(checked);
|
||||
|
||||
form.change('autoConnect', checked);
|
||||
|
||||
if (checked && !values.remember) {
|
||||
form.change('remember', true);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form className='loginForm' onSubmit={handleSubmit}>
|
||||
<div className='loginForm-items'>
|
||||
<div className='loginForm-item'>
|
||||
<Field label='Username' name='userName' component={InputField} autoComplete='off' />
|
||||
<OnChange name="userName">{onUserNameChange}</OnChange>
|
||||
</div>
|
||||
<div className='loginForm-item'>
|
||||
<Field
|
||||
label={passwordLabel}
|
||||
onFocus={() => setPasswordLabel(PASSWORD_LABEL)}
|
||||
onBlur={() => togglePasswordLabel(useStoredPassword(values.remember))}
|
||||
name='password'
|
||||
type='password'
|
||||
component={InputField}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</div>
|
||||
<div className='loginForm-actions'>
|
||||
<Field label='Save Password' name='remember' component={CheckboxField} />
|
||||
<OnChange name="remember">{onRememberChange}</OnChange>
|
||||
|
||||
<Button color='primary' onClick={onResetPassword}>Forgot Password</Button>
|
||||
</div>
|
||||
<div className='loginForm-item'>
|
||||
<Field name='selectedHost' component={KnownHosts} />
|
||||
<OnChange name="selectedHost">{setHost}</OnChange>
|
||||
</div>
|
||||
<div className='loginForm-actions'>
|
||||
<Field label='Auto Connect' name='autoConnect' component={CheckboxField} />
|
||||
<OnChange name="autoConnect">{onAutoConnectChange}</OnChange>
|
||||
</div>
|
||||
</div>
|
||||
<Button className='loginForm-submit rounded tall' color='primary' variant='contained' type='submit'>
|
||||
Login
|
||||
</Button>
|
||||
</form>
|
||||
)
|
||||
}}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
interface LoginFormProps {
|
||||
form: string;
|
||||
dispatch: Function;
|
||||
submit: Function;
|
||||
handleSubmit: FormSubmitHandler;
|
||||
onSubmit: any;
|
||||
onResetPassword: any;
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(reduxForm(propsMap)(LoginForm));
|
||||
export default LoginForm;
|
||||
|
|
|
|||
|
|
@ -1,21 +1,18 @@
|
|||
.registerForm {
|
||||
.RegisterForm {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.RegisterForm-column {
|
||||
width: 48%;
|
||||
}
|
||||
|
||||
.RegisterForm-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.RegisterForm-submit {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.registerForm-submit {
|
||||
width: 100%;
|
||||
/*padding is off, something in material-theme is causing it*/
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.column {
|
||||
width: 48%;
|
||||
flex: 0 1 auto;
|
||||
align-self: auto;
|
||||
}
|
||||
|
|
@ -1,67 +1,159 @@
|
|||
// eslint-disable-next-line
|
||||
import React, { Component } from 'react';
|
||||
import React, { Component, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Form, Field, reduxForm, change } from 'redux-form'
|
||||
import { Form, Field } from 'react-final-form';
|
||||
import { OnChange } from 'react-final-form-listeners';
|
||||
import setFieldTouched from 'final-form-set-field-touched'
|
||||
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
import { InputField, KnownHosts } from 'components';
|
||||
import { useReduxEffect } from 'hooks';
|
||||
import { ServerTypes } from 'store';
|
||||
import { FormKey } from 'types';
|
||||
|
||||
import './RegisterForm.css';
|
||||
|
||||
const RegisterForm = (props) => {
|
||||
const { dispatch, handleSubmit } = props;
|
||||
const RegisterForm = ({ onSubmit }: RegisterFormProps) => {
|
||||
const [emailRequired, setEmailRequired] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
const [emailError, setEmailError] = useState(null);
|
||||
const [passwordError, setPasswordError] = useState(null);
|
||||
const [userNameError, setUserNameError] = useState(null);
|
||||
|
||||
const onHostChange: any = ({ host, port }) => {
|
||||
dispatch(change(FormKey.REGISTER, 'host', host));
|
||||
dispatch(change(FormKey.REGISTER, 'port', port));
|
||||
const onHostChange = (host) => setEmailRequired(false);
|
||||
const onEmailChange = () => emailError && setEmailError(null);
|
||||
const onPasswordChange = () => passwordError && setPasswordError(null);
|
||||
const onUserNameChange = () => userNameError && setUserNameError(null);
|
||||
|
||||
useReduxEffect(() => {
|
||||
setEmailRequired(true);
|
||||
}, ServerTypes.REGISTRATION_REQUIRES_EMAIL);
|
||||
|
||||
useReduxEffect(({ error }) => {
|
||||
setError(error);
|
||||
}, ServerTypes.REGISTRATION_FAILED);
|
||||
|
||||
useReduxEffect(({ error }) => {
|
||||
setEmailError(error);
|
||||
}, ServerTypes.REGISTRATION_EMAIL_ERROR);
|
||||
|
||||
useReduxEffect(({ error }) => {
|
||||
setPasswordError(error);
|
||||
}, ServerTypes.REGISTRATION_PASSWORD_ERROR);
|
||||
|
||||
useReduxEffect(({ error }) => {
|
||||
setUserNameError(error);
|
||||
}, ServerTypes.REGISTRATION_USERNAME_ERROR);
|
||||
|
||||
const handleOnSubmit = form => {
|
||||
setError(null);
|
||||
onSubmit(form);
|
||||
}
|
||||
|
||||
const validate = values => {
|
||||
const errors: any = {};
|
||||
|
||||
if (!values.userName) {
|
||||
errors.userName = 'Required';
|
||||
} else if (userNameError) {
|
||||
errors.userName = userNameError;
|
||||
}
|
||||
|
||||
if (!values.password) {
|
||||
errors.password = 'Required';
|
||||
} else if (passwordError) {
|
||||
errors.password = passwordError;
|
||||
}
|
||||
|
||||
if (!values.passwordConfirm) {
|
||||
errors.passwordConfirm = 'Required';
|
||||
} else if (values.password !== values.passwordConfirm) {
|
||||
errors.passwordConfirm = 'Passwords don\'t match'
|
||||
}
|
||||
|
||||
if (!values.selectedHost) {
|
||||
errors.selectedHost = 'Required';
|
||||
}
|
||||
|
||||
if (emailRequired && !values.email) {
|
||||
errors.email = 'Required';
|
||||
} else if (emailError) {
|
||||
errors.email = emailError;
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
return (
|
||||
<Form className="registerForm row" onSubmit={handleSubmit} autoComplete="off">
|
||||
<div className="leftRegisterForm column" >
|
||||
<div className="registerForm-item">
|
||||
<Field name="selectedHost" component={KnownHosts} onChange={onHostChange} />
|
||||
{ /* Padding is off */ }
|
||||
</div>
|
||||
<div className="registerForm-item">
|
||||
<Field label="Country" name="country" component={InputField} />
|
||||
</div>
|
||||
<div className="registerForm-item">
|
||||
<Field label="Real Name" name="realName" component={InputField} />
|
||||
</div>
|
||||
<div className="registerForm-item">
|
||||
<Field label="Email" name="email" type="email" component={InputField} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="rightRegisterForm column">
|
||||
<div className="registerForm-item">
|
||||
<Field label="Player Name" name="user" component={InputField} />
|
||||
</div>
|
||||
<div className="registerForm-item">
|
||||
<Field label="Password" name="pass" type="password" component={InputField} />
|
||||
</div>
|
||||
<div className="registerForm-item">
|
||||
<Field label="Password (again)" name="passwordConfirm" type="password" component={InputField} />
|
||||
</div>
|
||||
<Button className="registerForm-submit tall" color="primary" variant="contained" type="submit">
|
||||
Register
|
||||
</Button>
|
||||
</div>
|
||||
<Form onSubmit={handleOnSubmit} validate={validate} mutators={{ setFieldTouched }}>
|
||||
{({ handleSubmit, form, ...args }) => {
|
||||
const { values } = form.getState();
|
||||
|
||||
if (emailRequired) {
|
||||
// Allow form render to complete
|
||||
setTimeout(() => form.mutators.setFieldTouched('email', true))
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<form className="RegisterForm" onSubmit={handleSubmit} autoComplete="off">
|
||||
<div className="RegisterForm-column">
|
||||
<div className="RegisterForm-item">
|
||||
<Field label="Player Name" name="userName" component={InputField} />
|
||||
<OnChange name="userName">{onUserNameChange}</OnChange>
|
||||
</div>
|
||||
<div className="RegisterForm-item">
|
||||
<Field label="Password" name="password" type="password" component={InputField} autoComplete='new-password' />
|
||||
<OnChange name="password">{onPasswordChange}</OnChange>
|
||||
</div>
|
||||
<div className="RegisterForm-item">
|
||||
<Field
|
||||
label="Confirm Password"
|
||||
name="passwordConfirm"
|
||||
type="password"
|
||||
component={InputField}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</div>
|
||||
<div className="RegisterForm-item">
|
||||
<Field name="selectedHost" component={KnownHosts} />
|
||||
<OnChange name="selectedHost">{onHostChange}</OnChange>
|
||||
</div>
|
||||
</div>
|
||||
<div className="RegisterForm-column" >
|
||||
<div className="RegisterForm-item">
|
||||
<Field label="Real Name" name="realName" component={InputField} autoComplete='off' />
|
||||
</div>
|
||||
<div className="RegisterForm-item">
|
||||
<Field label="Email" name="email" type="email" component={InputField} />
|
||||
<OnChange name="email">{onEmailChange}</OnChange>
|
||||
</div>
|
||||
<div className="RegisterForm-item">
|
||||
<Field label="Country" name="country" component={InputField} />
|
||||
</div>
|
||||
<Button className="RegisterForm-submit tall" color="primary" variant="contained" type="submit">
|
||||
Register
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{ error && (
|
||||
<div className="RegisterForm-item">
|
||||
<Typography color="error">{error}</Typography>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
|
||||
</Form >
|
||||
);
|
||||
};
|
||||
|
||||
const propsMap = {
|
||||
form: FormKey.REGISTER,
|
||||
};
|
||||
interface RegisterFormProps {
|
||||
onSubmit: any;
|
||||
}
|
||||
|
||||
const mapStateToProps = () => ({
|
||||
initialValues: {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(reduxForm(propsMap)(RegisterForm));
|
||||
export default RegisterForm;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,6 @@
|
|||
.RequestPasswordResetForm {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.RequestPasswordResetForm-MFA-Message {
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
||||
.RequestPasswordResetForm-Error {
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.RequestPasswordResetForm-item {
|
||||
|
|
@ -26,3 +19,7 @@
|
|||
.RequestPasswordResetForm-submit {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.selectedHost {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
// eslint-disable-next-line
|
||||
import React, { useState } from "react";
|
||||
import { connect } from 'react-redux';
|
||||
import { Form, Field, reduxForm, change } from 'redux-form'
|
||||
import { Form, Field } from 'react-final-form';
|
||||
import { OnChange } from 'react-final-form-listeners';
|
||||
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
import { InputField, KnownHosts } from 'components';
|
||||
import { FormKey } from 'types';
|
||||
|
|
@ -12,16 +14,10 @@ import './RequestPasswordResetForm.css';
|
|||
import { useReduxEffect } from 'hooks';
|
||||
import { ServerTypes } from 'store';
|
||||
|
||||
const RequestPasswordResetForm = (props) => {
|
||||
const { dispatch, handleSubmit } = props;
|
||||
const RequestPasswordResetForm = ({ onSubmit, skipTokenRequest }) => {
|
||||
const [errorMessage, setErrorMessage] = useState(false);
|
||||
const [isMFA, setIsMFA] = useState(false);
|
||||
|
||||
const onHostChange: any = ({ host, port }) => {
|
||||
dispatch(change(FormKey.RESET_PASSWORD_REQUEST, 'host', host));
|
||||
dispatch(change(FormKey.RESET_PASSWORD_REQUEST, 'port', port));
|
||||
}
|
||||
|
||||
useReduxEffect(() => {
|
||||
setErrorMessage(true);
|
||||
}, ServerTypes.RESET_PASSWORD_FAILED, []);
|
||||
|
|
@ -30,63 +26,73 @@ const RequestPasswordResetForm = (props) => {
|
|||
setIsMFA(true);
|
||||
}, ServerTypes.RESET_PASSWORD_CHALLENGE, []);
|
||||
|
||||
const onSubmit = (event) => {
|
||||
const handleOnSubmit = (form) => {
|
||||
setErrorMessage(false);
|
||||
handleSubmit(event);
|
||||
onSubmit(form);
|
||||
}
|
||||
|
||||
const validate = values => {
|
||||
const errors: any = {};
|
||||
|
||||
if (!values.userName) {
|
||||
errors.userName = 'Required';
|
||||
}
|
||||
if (isMFA && !values.email) {
|
||||
errors.email = 'Required';
|
||||
}
|
||||
if (!values.selectedHost) {
|
||||
errors.selectedHost = 'Required';
|
||||
}
|
||||
|
||||
return errors;
|
||||
};
|
||||
|
||||
return (
|
||||
<Form className="RequestPasswordResetForm" onSubmit={onSubmit}>
|
||||
<div className="RequestPasswordResetForm-items">
|
||||
{errorMessage ? (
|
||||
<div className="RequestPasswordResetForm-Error">Request Password Reset Failed, please try again</div>
|
||||
) : null}
|
||||
<div className="RequestPasswordResetForm-item">
|
||||
<Field label="Username" name="user" component={InputField} autoComplete="username" />
|
||||
</div>
|
||||
{isMFA ? (
|
||||
<div className="RequestPasswordResetForm-item">
|
||||
<div className="RequestPasswordResetForm-MFA-Message">Server has multi-factor authentication enabled</div>
|
||||
<Field label="Email" name="email" component={InputField} autoComplete="email" />
|
||||
</div>
|
||||
) : null}
|
||||
<div className="RequestPasswordResetForm-item">
|
||||
<Field name='selectedHost' component={KnownHosts} onChange={onHostChange} />
|
||||
</div>
|
||||
</div>
|
||||
<Button className="RequestPasswordResetForm-submit rounded tall" color="primary" variant="contained" type="submit">
|
||||
Request Reset Token
|
||||
</Button>
|
||||
<Form onSubmit={handleOnSubmit} validate={validate}>
|
||||
{({ handleSubmit, form }) => {
|
||||
const onHostChange: any = ({ userName }) => {
|
||||
form.change('userName', userName);
|
||||
setIsMFA(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="RequestPasswordResetForm" onSubmit={handleSubmit}>
|
||||
<div className="RequestPasswordResetForm-items">
|
||||
<div className="RequestPasswordResetForm-item">
|
||||
<Field label="Username" name="userName" component={InputField} autoComplete="username" disabled={isMFA} />
|
||||
</div>
|
||||
{isMFA ? (
|
||||
<div className="RequestPasswordResetForm-item">
|
||||
<Field label="Email" name="email" component={InputField} autoComplete="email" />
|
||||
<div>Server has multi-factor authentication enabled</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="RequestPasswordResetForm-item selectedHost">
|
||||
<Field name='selectedHost' component={KnownHosts} disabled={isMFA} />
|
||||
<OnChange name="selectedHost">{onHostChange}</OnChange>
|
||||
</div>
|
||||
|
||||
{errorMessage && (
|
||||
<div className="RequestPasswordResetForm-item">
|
||||
<Typography color="error">Request password reset failed</Typography>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button className="RequestPasswordResetForm-submit rounded tall" color="primary" variant="contained" type="submit">
|
||||
Request Reset Token
|
||||
</Button>
|
||||
|
||||
<div>
|
||||
<Button color="primary" onClick={() => skipTokenRequest(form.getState().values.userName)}>
|
||||
I already have a reset token
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
const propsMap = {
|
||||
form: FormKey.RESET_PASSWORD_REQUEST,
|
||||
validate: values => {
|
||||
const errors: any = {};
|
||||
|
||||
if (!values.user) {
|
||||
errors.user = 'Required';
|
||||
}
|
||||
if (!values.host) {
|
||||
errors.host = 'Required';
|
||||
}
|
||||
if (!values.port) {
|
||||
errors.port = 'Required';
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
};
|
||||
|
||||
const mapStateToProps = () => ({
|
||||
initialValues: {
|
||||
// host: "mtg.tetrarch.co/servatrice",
|
||||
// port: "443"
|
||||
// host: "server.cockatrice.us",
|
||||
// port: "4748"
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(reduxForm(propsMap)(RequestPasswordResetForm));
|
||||
export default RequestPasswordResetForm;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
.ResetPasswordForm {
|
||||
width: 100%;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.ResetPasswordForm-item {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
// eslint-disable-next-line
|
||||
import React, {useState} from "react";
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Form, Field, reduxForm, change } from 'redux-form'
|
||||
import { Form, Field } from 'react-final-form'
|
||||
import { OnChange } from 'react-final-form-listeners'
|
||||
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
import { InputField, KnownHosts } from 'components';
|
||||
import { FormKey } from 'types';
|
||||
|
|
@ -12,58 +14,18 @@ import './ResetPasswordForm.css';
|
|||
import { useReduxEffect } from '../../hooks';
|
||||
import { ServerTypes } from '../../store';
|
||||
|
||||
const ResetPasswordForm = (props) => {
|
||||
const { dispatch, handleSubmit } = props;
|
||||
|
||||
const ResetPasswordForm = ({ onSubmit, userName }) => {
|
||||
const [errorMessage, setErrorMessage] = useState(false);
|
||||
|
||||
|
||||
const onHostChange: any = ({ host, port }) => {
|
||||
dispatch(change(FormKey.RESET_PASSWORD, 'host', host));
|
||||
dispatch(change(FormKey.RESET_PASSWORD, 'port', port));
|
||||
}
|
||||
|
||||
useReduxEffect(() => {
|
||||
setErrorMessage(true);
|
||||
}, ServerTypes.RESET_PASSWORD_FAILED, []);
|
||||
|
||||
|
||||
return (
|
||||
<Form className="ResetPasswordForm" onSubmit={handleSubmit}>
|
||||
<div className="ResetPasswordForm-items">
|
||||
{errorMessage ? (
|
||||
<div><h3>Password Reset Failed, please try again</h3></div>
|
||||
) : null}
|
||||
<div className="ResetPasswordForm-item">
|
||||
<Field label="Username" name="user" component={InputField} autoComplete="username" />
|
||||
</div>
|
||||
<div className="ResetPasswordForm-item">
|
||||
<Field label="Token" name="token" component={InputField} />
|
||||
</div>
|
||||
<div className="ResetPasswordForm-item">
|
||||
<Field label="Password" name="newPassword" component={InputField} />
|
||||
</div>
|
||||
<div className="ResetPasswordForm-item">
|
||||
<Field label="Password Again" name="passwordAgain" component={InputField} />
|
||||
</div>
|
||||
<div className="ResetPasswordForm-item">
|
||||
<Field name='selectedHost' component={KnownHosts} onChange={onHostChange} />
|
||||
</div>
|
||||
</div>
|
||||
<Button className="ResetPasswordForm-submit rounded tall" color="primary" variant="contained" type="submit">
|
||||
Change Password
|
||||
</Button>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
const propsMap = {
|
||||
form: FormKey.RESET_PASSWORD,
|
||||
validate: values => {
|
||||
const validate = values => {
|
||||
const errors: any = {};
|
||||
|
||||
if (!values.user) {
|
||||
errors.user = 'Required';
|
||||
if (!values.userName) {
|
||||
errors.userName = 'Required';
|
||||
}
|
||||
if (!values.token) {
|
||||
errors.token = 'Required';
|
||||
|
|
@ -76,24 +38,47 @@ const propsMap = {
|
|||
} else if (values.newPassword !== values.passwordAgain) {
|
||||
errors.passwordAgain = 'Passwords don\'t match'
|
||||
}
|
||||
if (!values.host) {
|
||||
errors.host = 'Required';
|
||||
}
|
||||
if (!values.port) {
|
||||
errors.port = 'Required';
|
||||
if (!values.selectedHost) {
|
||||
errors.selectedHost = 'Required';
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form onSubmit={onSubmit} validate={validate} initialValues={{ userName }}>
|
||||
{({ handleSubmit, form }) => (
|
||||
<form className='ResetPasswordForm' onSubmit={handleSubmit}>
|
||||
<div className='ResetPasswordForm-items'>
|
||||
<div className='ResetPasswordForm-item'>
|
||||
<Field label='Username' name='userName' component={InputField} autoComplete='username' disabled={!!userName} />
|
||||
</div>
|
||||
<div className='ResetPasswordForm-item'>
|
||||
<Field label='Token' name='token' component={InputField} />
|
||||
</div>
|
||||
<div className='ResetPasswordForm-item'>
|
||||
<Field label='Password' name='newPassword' type='password' component={InputField} autoComplete='new-password' />
|
||||
</div>
|
||||
<div className='ResetPasswordForm-item'>
|
||||
<Field label='Password Again' name='passwordAgain' type='password' component={InputField} autoComplete='new-password' />
|
||||
</div>
|
||||
<div className='ResetPasswordForm-item'>
|
||||
<Field name='selectedHost' component={KnownHosts} disabled />
|
||||
</div>
|
||||
|
||||
{errorMessage && (
|
||||
<div className='ResetPasswordForm-item'>
|
||||
<Typography color="error">Password reset failed</Typography>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Button className='ResetPasswordForm-submit rounded tall' color='primary' variant='contained' type='submit'>
|
||||
Reset Password
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = () => ({
|
||||
initialValues: {
|
||||
// host: "mtg.tetrarch.co/servatrice",
|
||||
// port: "443"
|
||||
// host: "server.cockatrice.us",
|
||||
// port: "4748"
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(reduxForm(propsMap)(ResetPasswordForm));
|
||||
export default ResetPasswordForm;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue