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
13
webclient/package-lock.json
generated
13
webclient/package-lock.json
generated
|
@ -7100,6 +7100,11 @@
|
||||||
"@babel/runtime": "^7.10.0"
|
"@babel/runtime": "^7.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"final-form-set-field-touched": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/final-form-set-field-touched/-/final-form-set-field-touched-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-yvE5AAs9U3OgJQ9YF8NhSF0I0mJEECvOpkaXNqovloxji5Q6gOZ0DCIAyLAKHluGSpsXKUGORyBm8Hq0beZIqQ=="
|
||||||
|
},
|
||||||
"finalhandler": {
|
"finalhandler": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||||
|
@ -13005,6 +13010,14 @@
|
||||||
"@babel/runtime": "^7.15.4"
|
"@babel/runtime": "^7.15.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-final-form-listeners": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-final-form-listeners/-/react-final-form-listeners-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-OrdCNxSS4JQS/EXD+R530kZKFqaPfa+WcXPgVro/h4BpaBDF/Ja+BtHyCzDezCIb5rWaGGdOJIj+tN2YdtvrXg==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.12.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"dexie": "^3.0.3",
|
"dexie": "^3.0.3",
|
||||||
"final-form": "^4.20.4",
|
"final-form": "^4.20.4",
|
||||||
|
"final-form-set-field-touched": "^1.0.1",
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-final-form": "^6.5.7",
|
"react-final-form": "^6.5.7",
|
||||||
|
"react-final-form-listeners": "^1.0.3",
|
||||||
"react-redux": "^7.2.6",
|
"react-redux": "^7.2.6",
|
||||||
"react-router-dom": "^5.3.0",
|
"react-router-dom": "^5.3.0",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
|
|
|
@ -2,8 +2,8 @@ import React from 'react';
|
||||||
import Checkbox from '@material-ui/core/Checkbox';
|
import Checkbox from '@material-ui/core/Checkbox';
|
||||||
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
|
|
||||||
const CheckboxField = ({ input, label }) => {
|
const CheckboxField = (props) => {
|
||||||
const { value, onChange } = input;
|
const { input: { value, onChange }, label, ...args } = props;
|
||||||
|
|
||||||
// @TODO this isnt unchecking properly
|
// @TODO this isnt unchecking properly
|
||||||
return (
|
return (
|
||||||
|
@ -12,9 +12,10 @@ const CheckboxField = ({ input, label }) => {
|
||||||
label={label}
|
label={label}
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
{ ...args }
|
||||||
className="checkbox-field__box"
|
className="checkbox-field__box"
|
||||||
checked={!!value}
|
checked={!!value}
|
||||||
onChange={onChange}
|
onChange={(e, checked) => onChange(checked)}
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ const useStyles = makeStyles(theme => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const InputField = ({ input, label, name, autoComplete, type, meta: { touched, error, warning } }) => {
|
const InputField = ({ input, meta: { touched, error, warning }, ...args }) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -38,15 +38,12 @@ const InputField = ({ input, label, name, autoComplete, type, meta: { touched, e
|
||||||
) }
|
) }
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
|
{ ...input }
|
||||||
|
{ ...args }
|
||||||
className="rounded"
|
className="rounded"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
margin="dense"
|
margin="dense"
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
label={label}
|
|
||||||
name={name}
|
|
||||||
type={type}
|
|
||||||
autoComplete={autoComplete}
|
|
||||||
{ ...input }
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -29,7 +29,9 @@ const useStyles = makeStyles(theme => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const KnownHosts = ({ input: { onChange }, meta: { touched, error, warning } }) => {
|
const KnownHosts = (props) => {
|
||||||
|
const { input: { onChange }, meta, disabled } = props;
|
||||||
|
const { touched, error, warning } = meta;
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const [hostsState, setHostsState] = useState({
|
const [hostsState, setHostsState] = useState({
|
||||||
|
@ -169,6 +171,7 @@ const KnownHosts = ({ input: { onChange }, meta: { touched, error, warning } })
|
||||||
value={hostsState.selectedHost}
|
value={hostsState.selectedHost}
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
onChange={e => selectHost(e.target.value)}
|
onChange={e => selectHost(e.target.value)}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<Button value={hostsState.selectedHost} onClick={openAddKnownHostDialog}>
|
<Button value={hostsState.selectedHost} onClick={openAddKnownHostDialog}>
|
||||||
<span>Add new host</span>
|
<span>Add new host</span>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Common components
|
// Common components
|
||||||
export { default as Card } from './Card/Card';
|
export { default as Card } from './Card/Card';
|
||||||
export { default as CardDetails } from './CardDetails/CardDetails';
|
export { default as CardDetails } from './CardDetails/CardDetails';
|
||||||
|
export { default as CountryDropdown } from './CountryDropdown/CountryDropdown';
|
||||||
export { default as Header } from './Header/Header';
|
export { default as Header } from './Header/Header';
|
||||||
export { default as InputField } from './InputField/InputField';
|
export { default as InputField } from './InputField/InputField';
|
||||||
export { default as InputAction } from './InputAction/InputAction';
|
export { default as InputAction } from './InputAction/InputAction';
|
||||||
|
@ -16,7 +17,3 @@ export { default as ScrollToBottomOnChanges } from './ScrollToBottomOnChanges/Sc
|
||||||
// Guards
|
// Guards
|
||||||
export { default as AuthGuard } from './Guard/AuthGuard';
|
export { default as AuthGuard } from './Guard/AuthGuard';
|
||||||
export { default as ModGuard } from './Guard/ModGuard';
|
export { default as ModGuard } from './Guard/ModGuard';
|
||||||
|
|
||||||
// Dialogs
|
|
||||||
export { default as RequestPasswordResetDialog } from './RequestPasswordResetDialog/RequestPasswordResetDialog';
|
|
||||||
export { default as ResetPasswordDialog } from './ResetPasswordDialog/ResetPasswordDialog';
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
|
|
||||||
import { AuthenticationService } from 'api';
|
import { AuthenticationService } from 'api';
|
||||||
import { RequestPasswordResetDialog, ResetPasswordDialog } from 'components';
|
import { RegistrationDialog, RequestPasswordResetDialog, ResetPasswordDialog } from 'dialogs';
|
||||||
import { LoginForm } from 'forms';
|
import { LoginForm } from 'forms';
|
||||||
import { useReduxEffect } from 'hooks';
|
import { useReduxEffect } from 'hooks';
|
||||||
import { Images } from 'images';
|
import { Images } from 'images';
|
||||||
|
@ -63,8 +63,10 @@ const Login = ({ state, description }: LoginProps) => {
|
||||||
const [hostIdToRemember, setHostIdToRemember] = useState(null);
|
const [hostIdToRemember, setHostIdToRemember] = useState(null);
|
||||||
const [dialogState, setDialogState] = useState({
|
const [dialogState, setDialogState] = useState({
|
||||||
passwordResetRequestDialog: false,
|
passwordResetRequestDialog: false,
|
||||||
resetPasswordDialog: false
|
resetPasswordDialog: false,
|
||||||
|
registrationDialog: false,
|
||||||
});
|
});
|
||||||
|
const [userToResetPassword, setUserToResetPassword] = useState(null);
|
||||||
|
|
||||||
useReduxEffect(() => {
|
useReduxEffect(() => {
|
||||||
closeRequestPasswordResetDialog();
|
closeRequestPasswordResetDialog();
|
||||||
|
@ -88,11 +90,7 @@ const Login = ({ state, description }: LoginProps) => {
|
||||||
return !isConnected && description?.length;
|
return !isConnected && description?.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createAccount = () => {
|
const onSubmitLogin = useCallback((loginForm) => {
|
||||||
console.log('Login.createAccount->openForgotPasswordDialog');
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSubmit = useCallback((loginForm) => {
|
|
||||||
const {
|
const {
|
||||||
userName,
|
userName,
|
||||||
password,
|
password,
|
||||||
|
@ -133,16 +131,43 @@ const Login = ({ state, description }: LoginProps) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRequestPasswordResetDialogSubmit = async ({ user, email, host, port }) => {
|
const handleRegistrationDialogSubmit = (form) => {
|
||||||
|
const { userName, password, email, country, realName, selectedHost } = form;
|
||||||
|
|
||||||
|
AuthenticationService.register({
|
||||||
|
...getHostPort(selectedHost),
|
||||||
|
userName,
|
||||||
|
password,
|
||||||
|
email,
|
||||||
|
country,
|
||||||
|
realName,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRequestPasswordResetDialogSubmit = (form) => {
|
||||||
|
const { userName, email, selectedHost } = form;
|
||||||
|
const { host, port } = getHostPort(selectedHost);
|
||||||
|
|
||||||
if (email) {
|
if (email) {
|
||||||
AuthenticationService.resetPasswordChallenge({ user, email, host, port } as any);
|
AuthenticationService.resetPasswordChallenge({ userName, email, host, port } as any);
|
||||||
} else {
|
} else {
|
||||||
AuthenticationService.resetPasswordRequest({ user, host, port } as any);
|
setUserToResetPassword(userName);
|
||||||
|
AuthenticationService.resetPasswordRequest({ userName, host, port } as any);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleResetPasswordDialogSubmit = async ({ user, token, newPassword, passwordAgain, host, port }) => {
|
const handleResetPasswordDialogSubmit = ({ userName, token, newPassword, selectedHost }) => {
|
||||||
AuthenticationService.resetPassword({ user, token, newPassword, host, port } as any);
|
const { host, port } = getHostPort(selectedHost);
|
||||||
|
AuthenticationService.resetPassword({ userName, token, newPassword, host, port } as any);
|
||||||
|
};
|
||||||
|
|
||||||
|
const skipTokenRequest = (userName) => {
|
||||||
|
setUserToResetPassword(userName);
|
||||||
|
|
||||||
|
setDialogState(s => ({ ...s,
|
||||||
|
passwordResetRequestDialog: false,
|
||||||
|
resetPasswordDialog: true,
|
||||||
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeRequestPasswordResetDialog = () => {
|
const closeRequestPasswordResetDialog = () => {
|
||||||
|
@ -161,6 +186,14 @@ const Login = ({ state, description }: LoginProps) => {
|
||||||
setDialogState(s => ({ ...s, resetPasswordDialog: true }));
|
setDialogState(s => ({ ...s, resetPasswordDialog: true }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const closeRegistrationDialog = () => {
|
||||||
|
setDialogState(s => ({ ...s, registrationDialog: false }));
|
||||||
|
}
|
||||||
|
|
||||||
|
const openRegistrationDialog = () => {
|
||||||
|
setDialogState(s => ({ ...s, registrationDialog: true }));
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'login overflow-scroll ' + classes.root}>
|
<div className={'login overflow-scroll ' + classes.root}>
|
||||||
{ isConnected && <Redirect from="*" to={RouteEnum.SERVER} />}
|
{ isConnected && <Redirect from="*" to={RouteEnum.SERVER} />}
|
||||||
|
@ -175,7 +208,7 @@ const Login = ({ state, description }: LoginProps) => {
|
||||||
<Typography variant="h1">Login</Typography>
|
<Typography variant="h1">Login</Typography>
|
||||||
<Typography variant="subtitle1">A cross-platform virtual tabletop for multiplayer card games.</Typography>
|
<Typography variant="subtitle1">A cross-platform virtual tabletop for multiplayer card games.</Typography>
|
||||||
<div className="login-form">
|
<div className="login-form">
|
||||||
<LoginForm onSubmit={onSubmit} />
|
<LoginForm onSubmit={onSubmitLogin} onResetPassword={openRequestPasswordResetDialog} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -189,7 +222,7 @@ const Login = ({ state, description }: LoginProps) => {
|
||||||
<div className="login-footer">
|
<div className="login-footer">
|
||||||
<div className="login-footer_register">
|
<div className="login-footer_register">
|
||||||
<span>Not registered yet?</span>
|
<span>Not registered yet?</span>
|
||||||
<Button color="primary" onClick={createAccount}>Create an account</Button>
|
<Button color="primary" onClick={openRegistrationDialog}>Create an account</Button>
|
||||||
</div>
|
</div>
|
||||||
<Typography variant="subtitle2" className="login-footer__copyright">
|
<Typography variant="subtitle2" className="login-footer__copyright">
|
||||||
Cockatrice is an open source project. { new Date().getUTCFullYear() }
|
Cockatrice is an open source project. { new Date().getUTCFullYear() }
|
||||||
|
@ -236,16 +269,24 @@ const Login = ({ state, description }: LoginProps) => {
|
||||||
</Paper>
|
</Paper>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<RegistrationDialog
|
||||||
|
isOpen={dialogState.registrationDialog}
|
||||||
|
onSubmit={handleRegistrationDialogSubmit}
|
||||||
|
handleClose={closeRegistrationDialog}
|
||||||
|
/>
|
||||||
|
|
||||||
<RequestPasswordResetDialog
|
<RequestPasswordResetDialog
|
||||||
isOpen={dialogState.passwordResetRequestDialog}
|
isOpen={dialogState.passwordResetRequestDialog}
|
||||||
onSubmit={handleRequestPasswordResetDialogSubmit}
|
onSubmit={handleRequestPasswordResetDialogSubmit}
|
||||||
handleClose={closeRequestPasswordResetDialog}
|
handleClose={closeRequestPasswordResetDialog}
|
||||||
|
skipTokenRequest={skipTokenRequest}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ResetPasswordDialog
|
<ResetPasswordDialog
|
||||||
isOpen={dialogState.resetPasswordDialog}
|
isOpen={dialogState.resetPasswordDialog}
|
||||||
onSubmit={handleResetPasswordDialogSubmit}
|
onSubmit={handleResetPasswordDialogSubmit}
|
||||||
handleClose={closeResetPasswordDialog}
|
handleClose={closeResetPasswordDialog}
|
||||||
|
userName={userToResetPassword}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,3 +3,8 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dialog-content {
|
||||||
|
width: 700px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
|
@ -10,13 +10,13 @@ import { RegisterForm } from 'forms';
|
||||||
|
|
||||||
import './RegistrationDialog.css';
|
import './RegistrationDialog.css';
|
||||||
|
|
||||||
const RegistrationDialog = ({ classes, handleClose, isOpen }: any) => {
|
const RegistrationDialog = ({ classes, handleClose, isOpen, onSubmit }: any) => {
|
||||||
const handleOnClose = () => {
|
const handleOnClose = () => {
|
||||||
handleClose();
|
handleClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog onClose={handleOnClose} open={isOpen}>
|
<Dialog className="RegistrationDialog" onClose={handleOnClose} open={isOpen} maxWidth='xl'>
|
||||||
<DialogTitle disableTypography className="dialog-title">
|
<DialogTitle disableTypography className="dialog-title">
|
||||||
<Typography variant="h6">Create New Account</Typography>
|
<Typography variant="h6">Create New Account</Typography>
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ const RegistrationDialog = ({ classes, handleClose, isOpen }: any) => {
|
||||||
</IconButton>
|
</IconButton>
|
||||||
) : null}
|
) : null}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent className="dialog-content">
|
||||||
<RegisterForm onSubmit={handleOnClose}></RegisterForm>
|
<RegisterForm onSubmit={onSubmit}></RegisterForm>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { RequestPasswordResetForm } from 'forms';
|
||||||
|
|
||||||
import './RequestPasswordResetDialog.css';
|
import './RequestPasswordResetDialog.css';
|
||||||
|
|
||||||
const RequestPasswordResetDialog = ({ classes, handleClose, isOpen, onSubmit }: any) => {
|
const RequestPasswordResetDialog = ({ classes, handleClose, isOpen, onSubmit, skipTokenRequest }: any) => {
|
||||||
const handleOnClose = () => {
|
const handleOnClose = () => {
|
||||||
handleClose();
|
handleClose();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ const RequestPasswordResetDialog = ({ classes, handleClose, isOpen, onSubmit }:
|
||||||
) : null}
|
) : null}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<RequestPasswordResetForm onSubmit={onSubmit}></RequestPasswordResetForm>
|
<RequestPasswordResetForm onSubmit={onSubmit} skipTokenRequest={skipTokenRequest}></RequestPasswordResetForm>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
|
@ -10,7 +10,7 @@ import { ResetPasswordForm } from 'forms';
|
||||||
|
|
||||||
import './ResetPasswordDialog.css';
|
import './ResetPasswordDialog.css';
|
||||||
|
|
||||||
const ResetPasswordDialog = ({ classes, handleClose, isOpen, onSubmit }: any) => {
|
const ResetPasswordDialog = ({ classes, handleClose, isOpen, onSubmit, userName }: any) => {
|
||||||
const handleOnClose = () => {
|
const handleOnClose = () => {
|
||||||
handleClose();
|
handleClose();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ const ResetPasswordDialog = ({ classes, handleClose, isOpen, onSubmit }: any) =>
|
||||||
) : null}
|
) : null}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<ResetPasswordForm onSubmit={onSubmit}/>
|
<ResetPasswordForm onSubmit={onSubmit} userName={userName}/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
|
@ -1,3 +1,5 @@
|
||||||
export { default as CardImportDialog } from './CardImportDialog/CardImportDialog';
|
export { default as CardImportDialog } from './CardImportDialog/CardImportDialog';
|
||||||
export { default as KnownHostDialog } from './KnownHostDialog/KnownHostDialog';
|
export { default as KnownHostDialog } from './KnownHostDialog/KnownHostDialog';
|
||||||
export { default as RegistrationDialog } from './RegistrationDialog/RegistrationDialog';
|
export { default as RegistrationDialog } from './RegistrationDialog/RegistrationDialog';
|
||||||
|
export { default as RequestPasswordResetDialog } from './RequestPasswordResetDialog/RequestPasswordResetDialog';
|
||||||
|
export { default as ResetPasswordDialog } from './ResetPasswordDialog/ResetPasswordDialog';
|
||||||
|
|
|
@ -10,9 +10,29 @@ import { InputField } from 'components';
|
||||||
|
|
||||||
import './KnownHostForm.css';
|
import './KnownHostForm.css';
|
||||||
|
|
||||||
function KnownHostForm({ host, onRemove, onSubmit }) {
|
const KnownHostForm = ({ host, onRemove, onSubmit }) => {
|
||||||
const [confirmDelete, setConfirmDelete] = useState(false);
|
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 (
|
return (
|
||||||
<Form
|
<Form
|
||||||
initialValues={{
|
initialValues={{
|
||||||
|
@ -22,25 +42,7 @@ function KnownHostForm({ host, onRemove, onSubmit }) {
|
||||||
port: host?.port,
|
port: host?.port,
|
||||||
}}
|
}}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
validate={values => {
|
validate={validate}
|
||||||
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;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{({ handleSubmit }) => (
|
{({ handleSubmit }) => (
|
||||||
<form className="KnownHostForm" onSubmit={handleSubmit}>
|
<form className="KnownHostForm" onSubmit={handleSubmit}>
|
||||||
|
@ -74,7 +76,7 @@ function KnownHostForm({ host, onRemove, onSubmit }) {
|
||||||
) }
|
) }
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const mapStateToProps = () => ({
|
const mapStateToProps = () => ({
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
import React, { Component, useCallback, useEffect, useState, useRef } from 'react';
|
import React, { Component, useCallback, useEffect, useState, useRef } from 'react';
|
||||||
import { connect } from 'react-redux';
|
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';
|
import Button from '@material-ui/core/Button';
|
||||||
|
|
||||||
|
@ -16,151 +17,142 @@ import './LoginForm.css';
|
||||||
const PASSWORD_LABEL = 'Password';
|
const PASSWORD_LABEL = 'Password';
|
||||||
const STORED_PASSWORD_LABEL = '* SAVED *';
|
const STORED_PASSWORD_LABEL = '* SAVED *';
|
||||||
|
|
||||||
const LoginForm: any = ({ dispatch, form, submit, handleSubmit }: LoginFormProps) => {
|
const LoginForm = ({ onSubmit, onResetPassword }: LoginFormProps) => {
|
||||||
const password: any = useRef();
|
|
||||||
const [host, setHost] = useState(null);
|
const [host, setHost] = useState(null);
|
||||||
const [remember, setRemember] = useState(false);
|
|
||||||
const [passwordLabel, setPasswordLabel] = useState(PASSWORD_LABEL);
|
const [passwordLabel, setPasswordLabel] = useState(PASSWORD_LABEL);
|
||||||
const [hasStoredPassword, useStoredPassword] = useState(false);
|
const [autoConnect, setAutoConnect] = useAutoConnect();
|
||||||
|
|
||||||
const [autoConnect, setAutoConnect] = useAutoConnect(() => {
|
const validate = values => {
|
||||||
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 errors: any = {};
|
const errors: any = {};
|
||||||
|
|
||||||
if (!values.user) {
|
if (!values.userName) {
|
||||||
errors.user = 'Required';
|
errors.userName = 'Required';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!values.password && !values.selectedHost?.hashedPassword) {
|
if (!values.password && !values.selectedHost?.hashedPassword) {
|
||||||
errors.password = 'Required';
|
errors.password = 'Required';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!values.selectedHost) {
|
if (!values.selectedHost) {
|
||||||
errors.selectedHost = 'Required';
|
errors.selectedHost = 'Required';
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors;
|
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 {
|
interface LoginFormProps {
|
||||||
form: string;
|
onSubmit: any;
|
||||||
dispatch: Function;
|
onResetPassword: any;
|
||||||
submit: Function;
|
|
||||||
handleSubmit: FormSubmitHandler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
export default LoginForm;
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(reduxForm(propsMap)(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%;
|
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
|
// eslint-disable-next-line
|
||||||
import React, { Component } from 'react';
|
import React, { Component, useState } from 'react';
|
||||||
import { connect } from 'react-redux';
|
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 Button from '@material-ui/core/Button';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
import { InputField, KnownHosts } from 'components';
|
import { InputField, KnownHosts } from 'components';
|
||||||
|
import { useReduxEffect } from 'hooks';
|
||||||
|
import { ServerTypes } from 'store';
|
||||||
import { FormKey } from 'types';
|
import { FormKey } from 'types';
|
||||||
|
|
||||||
import './RegisterForm.css';
|
import './RegisterForm.css';
|
||||||
|
|
||||||
const RegisterForm = (props) => {
|
const RegisterForm = ({ onSubmit }: RegisterFormProps) => {
|
||||||
const { dispatch, handleSubmit } = props;
|
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 }) => {
|
const onHostChange = (host) => setEmailRequired(false);
|
||||||
dispatch(change(FormKey.REGISTER, 'host', host));
|
const onEmailChange = () => emailError && setEmailError(null);
|
||||||
dispatch(change(FormKey.REGISTER, 'port', port));
|
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 (
|
return (
|
||||||
<Form className="registerForm row" onSubmit={handleSubmit} autoComplete="off">
|
<Form onSubmit={handleOnSubmit} validate={validate} mutators={{ setFieldTouched }}>
|
||||||
<div className="leftRegisterForm column" >
|
{({ handleSubmit, form, ...args }) => {
|
||||||
<div className="registerForm-item">
|
const { values } = form.getState();
|
||||||
<Field name="selectedHost" component={KnownHosts} onChange={onHostChange} />
|
|
||||||
{ /* Padding is off */ }
|
if (emailRequired) {
|
||||||
</div>
|
// Allow form render to complete
|
||||||
<div className="registerForm-item">
|
setTimeout(() => form.mutators.setFieldTouched('email', true))
|
||||||
<Field label="Country" name="country" component={InputField} />
|
}
|
||||||
</div>
|
|
||||||
<div className="registerForm-item">
|
return (
|
||||||
<Field label="Real Name" name="realName" component={InputField} />
|
<>
|
||||||
</div>
|
<form className="RegisterForm" onSubmit={handleSubmit} autoComplete="off">
|
||||||
<div className="registerForm-item">
|
<div className="RegisterForm-column">
|
||||||
<Field label="Email" name="email" type="email" component={InputField} />
|
<div className="RegisterForm-item">
|
||||||
</div>
|
<Field label="Player Name" name="userName" component={InputField} />
|
||||||
</div>
|
<OnChange name="userName">{onUserNameChange}</OnChange>
|
||||||
<div className="rightRegisterForm column">
|
</div>
|
||||||
<div className="registerForm-item">
|
<div className="RegisterForm-item">
|
||||||
<Field label="Player Name" name="user" component={InputField} />
|
<Field label="Password" name="password" type="password" component={InputField} autoComplete='new-password' />
|
||||||
</div>
|
<OnChange name="password">{onPasswordChange}</OnChange>
|
||||||
<div className="registerForm-item">
|
</div>
|
||||||
<Field label="Password" name="pass" type="password" component={InputField} />
|
<div className="RegisterForm-item">
|
||||||
</div>
|
<Field
|
||||||
<div className="registerForm-item">
|
label="Confirm Password"
|
||||||
<Field label="Password (again)" name="passwordConfirm" type="password" component={InputField} />
|
name="passwordConfirm"
|
||||||
</div>
|
type="password"
|
||||||
<Button className="registerForm-submit tall" color="primary" variant="contained" type="submit">
|
component={InputField}
|
||||||
Register
|
autoComplete='new-password'
|
||||||
</Button>
|
/>
|
||||||
</div>
|
</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 >
|
</Form >
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const propsMap = {
|
interface RegisterFormProps {
|
||||||
form: FormKey.REGISTER,
|
onSubmit: any;
|
||||||
};
|
}
|
||||||
|
|
||||||
const mapStateToProps = () => ({
|
export default RegisterForm;
|
||||||
initialValues: {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(reduxForm(propsMap)(RegisterForm));
|
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
.RequestPasswordResetForm {
|
.RequestPasswordResetForm {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
padding-bottom: 15px;
|
||||||
|
|
||||||
.RequestPasswordResetForm-MFA-Message {
|
|
||||||
margin-top: -20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.RequestPasswordResetForm-Error {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.RequestPasswordResetForm-item {
|
.RequestPasswordResetForm-item {
|
||||||
|
@ -26,3 +19,7 @@
|
||||||
.RequestPasswordResetForm-submit {
|
.RequestPasswordResetForm-submit {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selectedHost {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { connect } from 'react-redux';
|
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 Button from '@material-ui/core/Button';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
import { InputField, KnownHosts } from 'components';
|
import { InputField, KnownHosts } from 'components';
|
||||||
import { FormKey } from 'types';
|
import { FormKey } from 'types';
|
||||||
|
@ -12,16 +14,10 @@ import './RequestPasswordResetForm.css';
|
||||||
import { useReduxEffect } from 'hooks';
|
import { useReduxEffect } from 'hooks';
|
||||||
import { ServerTypes } from 'store';
|
import { ServerTypes } from 'store';
|
||||||
|
|
||||||
const RequestPasswordResetForm = (props) => {
|
const RequestPasswordResetForm = ({ onSubmit, skipTokenRequest }) => {
|
||||||
const { dispatch, handleSubmit } = props;
|
|
||||||
const [errorMessage, setErrorMessage] = useState(false);
|
const [errorMessage, setErrorMessage] = useState(false);
|
||||||
const [isMFA, setIsMFA] = 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(() => {
|
useReduxEffect(() => {
|
||||||
setErrorMessage(true);
|
setErrorMessage(true);
|
||||||
}, ServerTypes.RESET_PASSWORD_FAILED, []);
|
}, ServerTypes.RESET_PASSWORD_FAILED, []);
|
||||||
|
@ -30,63 +26,73 @@ const RequestPasswordResetForm = (props) => {
|
||||||
setIsMFA(true);
|
setIsMFA(true);
|
||||||
}, ServerTypes.RESET_PASSWORD_CHALLENGE, []);
|
}, ServerTypes.RESET_PASSWORD_CHALLENGE, []);
|
||||||
|
|
||||||
const onSubmit = (event) => {
|
const handleOnSubmit = (form) => {
|
||||||
setErrorMessage(false);
|
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 (
|
return (
|
||||||
<Form className="RequestPasswordResetForm" onSubmit={onSubmit}>
|
<Form onSubmit={handleOnSubmit} validate={validate}>
|
||||||
<div className="RequestPasswordResetForm-items">
|
{({ handleSubmit, form }) => {
|
||||||
{errorMessage ? (
|
const onHostChange: any = ({ userName }) => {
|
||||||
<div className="RequestPasswordResetForm-Error">Request Password Reset Failed, please try again</div>
|
form.change('userName', userName);
|
||||||
) : null}
|
setIsMFA(false);
|
||||||
<div className="RequestPasswordResetForm-item">
|
}
|
||||||
<Field label="Username" name="user" component={InputField} autoComplete="username" />
|
|
||||||
</div>
|
return (
|
||||||
{isMFA ? (
|
<form className="RequestPasswordResetForm" onSubmit={handleSubmit}>
|
||||||
<div className="RequestPasswordResetForm-item">
|
<div className="RequestPasswordResetForm-items">
|
||||||
<div className="RequestPasswordResetForm-MFA-Message">Server has multi-factor authentication enabled</div>
|
<div className="RequestPasswordResetForm-item">
|
||||||
<Field label="Email" name="email" component={InputField} autoComplete="email" />
|
<Field label="Username" name="userName" component={InputField} autoComplete="username" disabled={isMFA} />
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
{isMFA ? (
|
||||||
<div className="RequestPasswordResetForm-item">
|
<div className="RequestPasswordResetForm-item">
|
||||||
<Field name='selectedHost' component={KnownHosts} onChange={onHostChange} />
|
<Field label="Email" name="email" component={InputField} autoComplete="email" />
|
||||||
</div>
|
<div>Server has multi-factor authentication enabled</div>
|
||||||
</div>
|
</div>
|
||||||
<Button className="RequestPasswordResetForm-submit rounded tall" color="primary" variant="contained" type="submit">
|
) : null}
|
||||||
Request Reset Token
|
<div className="RequestPasswordResetForm-item selectedHost">
|
||||||
</Button>
|
<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>
|
</Form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const propsMap = {
|
export default RequestPasswordResetForm;
|
||||||
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));
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
.ResetPasswordForm {
|
.ResetPasswordForm {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
padding-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ResetPasswordForm-item {
|
.ResetPasswordForm-item {
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
import React, {useState} from "react";
|
import React, { useEffect, useState } from 'react';
|
||||||
import { connect } from 'react-redux';
|
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 Button from '@material-ui/core/Button';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
import { InputField, KnownHosts } from 'components';
|
import { InputField, KnownHosts } from 'components';
|
||||||
import { FormKey } from 'types';
|
import { FormKey } from 'types';
|
||||||
|
@ -12,58 +14,18 @@ import './ResetPasswordForm.css';
|
||||||
import { useReduxEffect } from '../../hooks';
|
import { useReduxEffect } from '../../hooks';
|
||||||
import { ServerTypes } from '../../store';
|
import { ServerTypes } from '../../store';
|
||||||
|
|
||||||
const ResetPasswordForm = (props) => {
|
const ResetPasswordForm = ({ onSubmit, userName }) => {
|
||||||
const { dispatch, handleSubmit } = props;
|
|
||||||
|
|
||||||
const [errorMessage, setErrorMessage] = useState(false);
|
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(() => {
|
useReduxEffect(() => {
|
||||||
setErrorMessage(true);
|
setErrorMessage(true);
|
||||||
}, ServerTypes.RESET_PASSWORD_FAILED, []);
|
}, ServerTypes.RESET_PASSWORD_FAILED, []);
|
||||||
|
|
||||||
|
const validate = values => {
|
||||||
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 errors: any = {};
|
const errors: any = {};
|
||||||
|
|
||||||
if (!values.user) {
|
if (!values.userName) {
|
||||||
errors.user = 'Required';
|
errors.userName = 'Required';
|
||||||
}
|
}
|
||||||
if (!values.token) {
|
if (!values.token) {
|
||||||
errors.token = 'Required';
|
errors.token = 'Required';
|
||||||
|
@ -76,24 +38,47 @@ const propsMap = {
|
||||||
} else if (values.newPassword !== values.passwordAgain) {
|
} else if (values.newPassword !== values.passwordAgain) {
|
||||||
errors.passwordAgain = 'Passwords don\'t match'
|
errors.passwordAgain = 'Passwords don\'t match'
|
||||||
}
|
}
|
||||||
if (!values.host) {
|
if (!values.selectedHost) {
|
||||||
errors.host = 'Required';
|
errors.selectedHost = 'Required';
|
||||||
}
|
|
||||||
if (!values.port) {
|
|
||||||
errors.port = 'Required';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors;
|
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 = () => ({
|
export default ResetPasswordForm;
|
||||||
initialValues: {
|
|
||||||
// host: "mtg.tetrarch.co/servatrice",
|
|
||||||
// port: "443"
|
|
||||||
// host: "server.cockatrice.us",
|
|
||||||
// port: "4748"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(reduxForm(propsMap)(ResetPasswordForm));
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { APP_USER } from 'types';
|
||||||
|
|
||||||
type OnChange = () => void;
|
type OnChange = () => void;
|
||||||
|
|
||||||
export function useAutoConnect(onChange: OnChange) {
|
export function useAutoConnect() {
|
||||||
const [setting, setSetting] = useState(undefined);
|
const [setting, setSetting] = useState(undefined);
|
||||||
const [autoConnect, setAutoConnect] = useState(undefined);
|
const [autoConnect, setAutoConnect] = useState(undefined);
|
||||||
|
|
||||||
|
@ -31,8 +31,6 @@ export function useAutoConnect(onChange: OnChange) {
|
||||||
if (setting) {
|
if (setting) {
|
||||||
setting.autoConnect = autoConnect;
|
setting.autoConnect = autoConnect;
|
||||||
setting.save();
|
setting.save();
|
||||||
|
|
||||||
onChange();
|
|
||||||
}
|
}
|
||||||
}, [setting, autoConnect]);
|
}, [setting, autoConnect]);
|
||||||
|
|
||||||
|
|
|
@ -72,18 +72,37 @@ export const Actions = {
|
||||||
logs
|
logs
|
||||||
}),
|
}),
|
||||||
clearLogs: () => ({
|
clearLogs: () => ({
|
||||||
type: Types.CLEAR_LOGS
|
type: Types.CLEAR_LOGS,
|
||||||
|
}),
|
||||||
|
registrationRequiresEmail: () => ({
|
||||||
|
type: Types.REGISTRATION_REQUIRES_EMAIL,
|
||||||
|
}),
|
||||||
|
registrationFailed: (error) => ({
|
||||||
|
type: Types.REGISTRATION_FAILED,
|
||||||
|
error
|
||||||
|
}),
|
||||||
|
registrationEmailError: (error) => ({
|
||||||
|
type: Types.REGISTRATION_EMAIL_ERROR,
|
||||||
|
error
|
||||||
|
}),
|
||||||
|
registrationPasswordError: (error) => ({
|
||||||
|
type: Types.REGISTRATION_PASSWORD_ERROR,
|
||||||
|
error
|
||||||
|
}),
|
||||||
|
registrationUserNameError: (error) => ({
|
||||||
|
type: Types.REGISTRATION_USERNAME_ERROR,
|
||||||
|
error
|
||||||
}),
|
}),
|
||||||
resetPassword: () => ({
|
resetPassword: () => ({
|
||||||
type: Types.RESET_PASSWORD_REQUESTED
|
type: Types.RESET_PASSWORD_REQUESTED,
|
||||||
}),
|
}),
|
||||||
resetPasswordFailed: () => ({
|
resetPasswordFailed: () => ({
|
||||||
type: Types.RESET_PASSWORD_FAILED
|
type: Types.RESET_PASSWORD_FAILED,
|
||||||
}),
|
}),
|
||||||
resetPasswordChallenge: () => ({
|
resetPasswordChallenge: () => ({
|
||||||
type: Types.RESET_PASSWORD_CHALLENGE
|
type: Types.RESET_PASSWORD_CHALLENGE,
|
||||||
}),
|
}),
|
||||||
resetPasswordSuccess: () => ({
|
resetPasswordSuccess: () => ({
|
||||||
type: Types.RESET_PASSWORD_SUCCESS
|
type: Types.RESET_PASSWORD_SUCCESS,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,21 @@ export const Dispatch = {
|
||||||
serverMessage: message => {
|
serverMessage: message => {
|
||||||
store.dispatch(Actions.serverMessage(message));
|
store.dispatch(Actions.serverMessage(message));
|
||||||
},
|
},
|
||||||
|
registrationRequiresEmail: () => {
|
||||||
|
store.dispatch(Actions.registrationRequiresEmail());
|
||||||
|
},
|
||||||
|
registrationFailed: (error) => {
|
||||||
|
store.dispatch(Actions.registrationFailed(error));
|
||||||
|
},
|
||||||
|
registrationEmailError: (error) => {
|
||||||
|
store.dispatch(Actions.registrationEmailError(error));
|
||||||
|
},
|
||||||
|
registrationPasswordError: (error) => {
|
||||||
|
store.dispatch(Actions.registrationPasswordError(error));
|
||||||
|
},
|
||||||
|
registrationUserNameError: (error) => {
|
||||||
|
store.dispatch(Actions.registrationUserNameError(error));
|
||||||
|
},
|
||||||
resetPassword: () => {
|
resetPassword: () => {
|
||||||
store.dispatch(Actions.resetPassword());
|
store.dispatch(Actions.resetPassword());
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,6 +17,11 @@ export const Types = {
|
||||||
USER_LEFT: '[Server] User Left',
|
USER_LEFT: '[Server] User Left',
|
||||||
VIEW_LOGS: '[Server] View Logs',
|
VIEW_LOGS: '[Server] View Logs',
|
||||||
CLEAR_LOGS: '[Server] Clear Logs',
|
CLEAR_LOGS: '[Server] Clear Logs',
|
||||||
|
REGISTRATION_REQUIRES_EMAIL: '[Server] Registration Requires Email',
|
||||||
|
REGISTRATION_FAILED: '[Server] Registration Failed',
|
||||||
|
REGISTRATION_EMAIL_ERROR: '[Server] Registration Email Error',
|
||||||
|
REGISTRATION_PASSWORD_ERROR: '[Server] Registration Password Error',
|
||||||
|
REGISTRATION_USERNAME_ERROR: '[Server] Registration Username Error',
|
||||||
RESET_PASSWORD_REQUESTED: '[Server] Reset Password Requested',
|
RESET_PASSWORD_REQUESTED: '[Server] Reset Password Requested',
|
||||||
RESET_PASSWORD_FAILED: '[Server] Reset Password Failed',
|
RESET_PASSWORD_FAILED: '[Server] Reset Password Failed',
|
||||||
RESET_PASSWORD_CHALLENGE: '[Server] Reset Password Challenge',
|
RESET_PASSWORD_CHALLENGE: '[Server] Reset Password Challenge',
|
||||||
|
|
|
@ -20,6 +20,8 @@ export interface WebSocketConnectOptions {
|
||||||
hashedPassword?: string;
|
hashedPassword?: string;
|
||||||
newPassword?: string;
|
newPassword?: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
|
realName?: string;
|
||||||
|
country?: string;
|
||||||
autojoinrooms?: boolean;
|
autojoinrooms?: boolean;
|
||||||
keepalive?: number;
|
keepalive?: number;
|
||||||
clientid?: string;
|
clientid?: string;
|
||||||
|
|
|
@ -38,6 +38,8 @@ export class WebClient {
|
||||||
hashedPassword: '',
|
hashedPassword: '',
|
||||||
newPassword: '',
|
newPassword: '',
|
||||||
email: '',
|
email: '',
|
||||||
|
realName: '',
|
||||||
|
country: '',
|
||||||
clientid: null,
|
clientid: null,
|
||||||
reason: null,
|
reason: null,
|
||||||
autojoinrooms: true,
|
autojoinrooms: true,
|
||||||
|
|
|
@ -299,39 +299,300 @@ describe('SessionCommands', () => {
|
||||||
sendSessionCommandSpy.mockImplementation((_, callback) => callback(response));
|
sendSessionCommandSpy.mockImplementation((_, callback) => callback(response));
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should login user if registration accepted without email verification', () => {
|
describe('RespRegistrationAccepted', () => {
|
||||||
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
it('should call SessionCommands.login()', () => {
|
||||||
jest.spyOn(SessionPersistence, 'accountAwaitingActivation').mockImplementation(() => {});
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
SessionCommands.register();
|
expect(SessionCommands.login).toHaveBeenCalled();
|
||||||
|
|
||||||
expect(SessionCommands.login).toHaveBeenCalled();
|
})
|
||||||
expect(SessionPersistence.accountAwaitingActivation).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should prompt user if registration accepted with email verification', () => {
|
describe('RespRegistrationAcceptedNeedsActivation', () => {
|
||||||
const RespRegistrationAcceptedNeedsActivation = 'RespRegistrationAcceptedNeedsActivation';
|
const RespRegistrationAcceptedNeedsActivation = 'RespRegistrationAcceptedNeedsActivation';
|
||||||
response.responseCode = RespRegistrationAcceptedNeedsActivation;
|
|
||||||
webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAcceptedNeedsActivation =
|
|
||||||
RespRegistrationAcceptedNeedsActivation;
|
|
||||||
|
|
||||||
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
beforeEach(() => {
|
||||||
jest.spyOn(SessionPersistence, 'accountAwaitingActivation').mockImplementation(() => {});
|
response.responseCode = RespRegistrationAcceptedNeedsActivation;
|
||||||
|
webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAcceptedNeedsActivation =
|
||||||
|
RespRegistrationAcceptedNeedsActivation;
|
||||||
|
});
|
||||||
|
|
||||||
SessionCommands.register();
|
it('should call SessionPersistence.accountAwaitingActivation()', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
jest.spyOn(SessionPersistence, 'accountAwaitingActivation').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
expect(SessionCommands.login).not.toHaveBeenCalled();
|
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||||
expect(SessionPersistence.accountAwaitingActivation).toHaveBeenCalled();
|
expect(SessionPersistence.accountAwaitingActivation).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disconnect', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'disconnect').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should disconnect user if registration fails due to registration being disabled', () => {
|
describe('RespUserAlreadyExists', () => {
|
||||||
|
const RespUserAlreadyExists = 'RespUserAlreadyExists';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
response.responseCode = RespUserAlreadyExists;
|
||||||
|
webClient.protobuf.controller.Response.ResponseCode.RespUserAlreadyExists =
|
||||||
|
RespUserAlreadyExists;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call SessionPersistence.registrationUserNameError()', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
jest.spyOn(SessionPersistence, 'registrationUserNameError').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||||
|
expect(SessionPersistence.registrationUserNameError).toHaveBeenCalledWith(expect.any(String));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disconnect', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'disconnect').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RespUsernameInvalid', () => {
|
||||||
|
const RespUsernameInvalid = 'RespUsernameInvalid';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
response.responseCode = RespUsernameInvalid;
|
||||||
|
webClient.protobuf.controller.Response.ResponseCode.RespUsernameInvalid =
|
||||||
|
RespUsernameInvalid;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call SessionPersistence.registrationUserNameError()', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
jest.spyOn(SessionPersistence, 'registrationUserNameError').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||||
|
expect(SessionPersistence.registrationUserNameError).toHaveBeenCalledWith(expect.any(String));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disconnect', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'disconnect').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RespPasswordTooShort', () => {
|
||||||
|
const RespPasswordTooShort = 'RespPasswordTooShort';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
response.responseCode = RespPasswordTooShort;
|
||||||
|
webClient.protobuf.controller.Response.ResponseCode.RespPasswordTooShort =
|
||||||
|
RespPasswordTooShort;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call SessionPersistence.registrationPasswordError()', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
jest.spyOn(SessionPersistence, 'registrationPasswordError').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||||
|
expect(SessionPersistence.registrationPasswordError).toHaveBeenCalledWith(expect.any(String));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disconnect', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'disconnect').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RespEmailRequiredToRegister', () => {
|
||||||
|
const RespEmailRequiredToRegister = 'RespEmailRequiredToRegister';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
response.responseCode = RespEmailRequiredToRegister;
|
||||||
|
webClient.protobuf.controller.Response.ResponseCode.RespEmailRequiredToRegister =
|
||||||
|
RespEmailRequiredToRegister;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call SessionPersistence.registrationRequiresEmail()', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
jest.spyOn(SessionPersistence, 'registrationRequiresEmail').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||||
|
expect(SessionPersistence.registrationRequiresEmail).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disconnect', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'disconnect').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RespEmailBlackListed', () => {
|
||||||
|
const RespEmailBlackListed = 'RespEmailBlackListed';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
response.responseCode = RespEmailBlackListed;
|
||||||
|
webClient.protobuf.controller.Response.ResponseCode.RespEmailBlackListed =
|
||||||
|
RespEmailBlackListed;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call SessionPersistence.registrationEmailError()', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
jest.spyOn(SessionPersistence, 'registrationEmailError').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||||
|
expect(SessionPersistence.registrationEmailError).toHaveBeenCalledWith(expect.any(String));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disconnect', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'disconnect').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RespTooManyRequests', () => {
|
||||||
|
const RespTooManyRequests = 'RespTooManyRequests';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
response.responseCode = RespTooManyRequests;
|
||||||
|
webClient.protobuf.controller.Response.ResponseCode.RespTooManyRequests =
|
||||||
|
RespTooManyRequests;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call SessionPersistence.registrationEmailError()', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
jest.spyOn(SessionPersistence, 'registrationEmailError').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||||
|
expect(SessionPersistence.registrationEmailError).toHaveBeenCalledWith(expect.any(String));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disconnect', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'disconnect').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RespRegistrationDisabled', () => {
|
||||||
const RespRegistrationDisabled = 'RespRegistrationDisabled';
|
const RespRegistrationDisabled = 'RespRegistrationDisabled';
|
||||||
response.responseCode = RespRegistrationDisabled;
|
|
||||||
webClient.protobuf.controller.Response.ResponseCode.RespRegistrationDisabled = RespRegistrationDisabled;
|
|
||||||
|
|
||||||
SessionCommands.register();
|
beforeEach(() => {
|
||||||
|
response.responseCode = RespRegistrationDisabled;
|
||||||
|
webClient.protobuf.controller.Response.ResponseCode.RespRegistrationDisabled =
|
||||||
|
RespRegistrationDisabled;
|
||||||
|
});
|
||||||
|
|
||||||
expect(SessionCommands.updateStatus).toHaveBeenCalledWith(StatusEnum.DISCONNECTED, expect.any(String));
|
it('should call SessionPersistence.registrationFailed()', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
jest.spyOn(SessionPersistence, 'registrationFailed').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||||
|
expect(SessionPersistence.registrationFailed).toHaveBeenCalledWith(expect.any(String));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disconnect', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'disconnect').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RespUserIsBanned', () => {
|
||||||
|
const RespUserIsBanned = 'RespUserIsBanned';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
response.responseCode = RespUserIsBanned;
|
||||||
|
webClient.protobuf.controller.Response.ResponseCode.RespUserIsBanned =
|
||||||
|
RespUserIsBanned;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call SessionPersistence.registrationFailed()', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
jest.spyOn(SessionPersistence, 'registrationFailed').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||||
|
expect(SessionPersistence.registrationFailed).toHaveBeenCalledWith(expect.any(String));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disconnect', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'disconnect').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RespRegistrationFailed', () => {
|
||||||
|
const RespRegistrationFailed = 'RespRegistrationFailed';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
response.responseCode = RespRegistrationFailed;
|
||||||
|
webClient.protobuf.controller.Response.ResponseCode.RespRegistrationFailed =
|
||||||
|
RespRegistrationFailed;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call SessionPersistence.registrationFailed()', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
jest.spyOn(SessionPersistence, 'registrationFailed').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||||
|
expect(SessionPersistence.registrationFailed).toHaveBeenCalledWith(expect.any(String));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disconnect', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'disconnect').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('UnknownFailureReason', () => {
|
||||||
|
const UnknownFailureReason = 'UnknownFailureReason';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
response.responseCode = UnknownFailureReason;
|
||||||
|
webClient.protobuf.controller.Response.ResponseCode.UnknownFailureReason =
|
||||||
|
UnknownFailureReason;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call SessionPersistence.registrationFailed()', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'login').mockImplementation(() => {});
|
||||||
|
jest.spyOn(SessionPersistence, 'registrationFailed').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.login).not.toHaveBeenCalled();
|
||||||
|
expect(SessionPersistence.registrationFailed).toHaveBeenCalledWith(expect.any(String));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disconnect', () => {
|
||||||
|
jest.spyOn(SessionCommands, 'disconnect').mockImplementation(() => {});
|
||||||
|
SessionCommands.register();
|
||||||
|
|
||||||
|
expect(SessionCommands.disconnect).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -179,48 +179,41 @@ export class SessionCommands {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let error;
|
|
||||||
|
|
||||||
switch (raw.responseCode) {
|
switch (raw.responseCode) {
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAcceptedNeedsActivation:
|
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationAcceptedNeedsActivation:
|
||||||
SessionPersistence.accountAwaitingActivation();
|
SessionPersistence.accountAwaitingActivation();
|
||||||
break;
|
break;
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationDisabled:
|
|
||||||
error = 'Registration is currently disabled';
|
|
||||||
break;
|
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespUserAlreadyExists:
|
case webClient.protobuf.controller.Response.ResponseCode.RespUserAlreadyExists:
|
||||||
error = 'There is already an existing user with this username';
|
SessionPersistence.registrationUserNameError('Username is taken');
|
||||||
break;
|
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespEmailRequiredToRegister:
|
|
||||||
error = 'A valid email address is required to register';
|
|
||||||
break;
|
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespEmailBlackListed:
|
|
||||||
error = 'The email address provider used has been blocked from use';
|
|
||||||
break;
|
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespTooManyRequests:
|
|
||||||
error = 'This email address already has the maximum number of accounts you can register';
|
|
||||||
break;
|
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespPasswordTooShort:
|
|
||||||
error = 'Your password was too short';
|
|
||||||
break;
|
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespUserIsBanned:
|
|
||||||
error = NormalizeService.normalizeBannedUserError(raw.reasonStr, raw.endTime);
|
|
||||||
break;
|
break;
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespUsernameInvalid:
|
case webClient.protobuf.controller.Response.ResponseCode.RespUsernameInvalid:
|
||||||
console.error('ResponseCode.RespUsernameInvalid', raw.reasonStr);
|
console.error('ResponseCode.RespUsernameInvalid', raw.reasonStr);
|
||||||
error = 'Invalid username';
|
SessionPersistence.registrationUserNameError('Invalid username');
|
||||||
|
break;
|
||||||
|
case webClient.protobuf.controller.Response.ResponseCode.RespPasswordTooShort:
|
||||||
|
SessionPersistence.registrationPasswordError('Your password was too short');
|
||||||
|
break;
|
||||||
|
case webClient.protobuf.controller.Response.ResponseCode.RespEmailRequiredToRegister:
|
||||||
|
SessionPersistence.registrationRequiresEmail();
|
||||||
|
break;
|
||||||
|
case webClient.protobuf.controller.Response.ResponseCode.RespEmailBlackListed:
|
||||||
|
SessionPersistence.registrationEmailError('This email provider has been blocked');
|
||||||
|
break;
|
||||||
|
case webClient.protobuf.controller.Response.ResponseCode.RespTooManyRequests:
|
||||||
|
SessionPersistence.registrationEmailError('Max accounts reached for this email');
|
||||||
|
break;
|
||||||
|
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationDisabled:
|
||||||
|
SessionPersistence.registrationFailed('Registration is currently disabled');
|
||||||
|
break;
|
||||||
|
case webClient.protobuf.controller.Response.ResponseCode.RespUserIsBanned:
|
||||||
|
SessionPersistence.registrationFailed(NormalizeService.normalizeBannedUserError(raw.reasonStr, raw.endTime));
|
||||||
break;
|
break;
|
||||||
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationFailed:
|
case webClient.protobuf.controller.Response.ResponseCode.RespRegistrationFailed:
|
||||||
default:
|
default:
|
||||||
console.error('ResponseCode Type', raw.responseCode);
|
SessionPersistence.registrationFailed('Registration failed due to a server issue');
|
||||||
error = 'Registration failed due to a server issue';
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
|
||||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, `Registration Failed: ${error}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
SessionCommands.disconnect();
|
SessionCommands.disconnect();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -272,14 +265,14 @@ export class SessionCommands {
|
||||||
const resp = raw['.Response_ForgotPasswordRequest.ext'];
|
const resp = raw['.Response_ForgotPasswordRequest.ext'];
|
||||||
|
|
||||||
if (resp.challengeEmail) {
|
if (resp.challengeEmail) {
|
||||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Requesting MFA information');
|
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
|
||||||
SessionPersistence.resetPasswordChallenge();
|
SessionPersistence.resetPasswordChallenge();
|
||||||
} else {
|
} else {
|
||||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Password reset in progress');
|
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
|
||||||
SessionPersistence.resetPassword();
|
SessionPersistence.resetPassword();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Password reset failed, please try again');
|
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
|
||||||
SessionPersistence.resetPasswordFailed();
|
SessionPersistence.resetPasswordFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,10 +298,10 @@ export class SessionCommands {
|
||||||
|
|
||||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||||
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
|
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
|
||||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Password reset in progress');
|
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
|
||||||
SessionPersistence.resetPassword();
|
SessionPersistence.resetPassword();
|
||||||
} else {
|
} else {
|
||||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Password reset failed, please try again');
|
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
|
||||||
SessionPersistence.resetPasswordFailed();
|
SessionPersistence.resetPasswordFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,10 +328,10 @@ export class SessionCommands {
|
||||||
|
|
||||||
webClient.protobuf.sendSessionCommand(sc, raw => {
|
webClient.protobuf.sendSessionCommand(sc, raw => {
|
||||||
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
|
if (raw.responseCode === webClient.protobuf.controller.Response.ResponseCode.RespOk) {
|
||||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Password successfully updated');
|
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
|
||||||
SessionPersistence.resetPasswordSuccess();
|
SessionPersistence.resetPasswordSuccess();
|
||||||
} else {
|
} else {
|
||||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, 'Password update failed, please try again');
|
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, null);
|
||||||
SessionPersistence.resetPasswordFailed();
|
SessionPersistence.resetPasswordFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,26 @@ export class SessionPersistence {
|
||||||
console.log('Account activation failed, show an action here');
|
console.log('Account activation failed, show an action here');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static registrationRequiresEmail() {
|
||||||
|
ServerDispatch.registrationRequiresEmail();
|
||||||
|
}
|
||||||
|
|
||||||
|
static registrationFailed(error: string) {
|
||||||
|
ServerDispatch.registrationFailed(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static registrationEmailError(error: string) {
|
||||||
|
ServerDispatch.registrationEmailError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static registrationPasswordError(error: string) {
|
||||||
|
ServerDispatch.registrationPasswordError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static registrationUserNameError(error: string) {
|
||||||
|
ServerDispatch.registrationUserNameError(error);
|
||||||
|
}
|
||||||
|
|
||||||
static resetPasswordChallenge() {
|
static resetPasswordChallenge() {
|
||||||
ServerDispatch.resetPasswordChallenge();
|
ServerDispatch.resetPasswordChallenge();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue