Dev/jchamish/forgotpassword (#4481)
* Implementation of Forgotten Password Reset * Update webclient/src/hooks/useReduxEffect.tsx Co-authored-by: Zach H <zahalpern+github@gmail.com>
This commit is contained in:
parent
7c27e955d5
commit
73c5956ece
25 changed files with 447 additions and 7 deletions
|
@ -0,0 +1,5 @@
|
||||||
|
.dialog-title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Dialog from '@material-ui/core/Dialog';
|
||||||
|
import DialogContent from '@material-ui/core/DialogContent';
|
||||||
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
|
import CloseIcon from '@material-ui/icons/Close';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
|
import { RequestPasswordResetForm } from 'forms';
|
||||||
|
|
||||||
|
import './RequestPasswordResetDialog.css';
|
||||||
|
|
||||||
|
const RequestPasswordResetDialog = ({ classes, handleClose, isOpen, onSubmit }: any) => {
|
||||||
|
const handleOnClose = () => {
|
||||||
|
handleClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog onClose={handleOnClose} open={isOpen}>
|
||||||
|
<DialogTitle disableTypography className="dialog-title">
|
||||||
|
<Typography variant="h6">Request Password Reset</Typography>
|
||||||
|
|
||||||
|
{handleOnClose ? (
|
||||||
|
<IconButton onClick={handleOnClose}>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
) : null}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<RequestPasswordResetForm onSubmit={onSubmit}></RequestPasswordResetForm>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RequestPasswordResetDialog;
|
|
@ -0,0 +1,5 @@
|
||||||
|
.dialog-title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Dialog from '@material-ui/core/Dialog';
|
||||||
|
import DialogContent from '@material-ui/core/DialogContent';
|
||||||
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
|
import CloseIcon from '@material-ui/icons/Close';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
|
import { ResetPasswordForm } from 'forms';
|
||||||
|
|
||||||
|
import './ResetPasswordDialog.css';
|
||||||
|
|
||||||
|
const ResetPasswordDialog = ({ classes, handleClose, isOpen, onSubmit }: any) => {
|
||||||
|
const handleOnClose = () => {
|
||||||
|
handleClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog onClose={handleOnClose} open={isOpen}>
|
||||||
|
<DialogTitle disableTypography className="dialog-title">
|
||||||
|
<Typography variant="h6">Reset Password</Typography>
|
||||||
|
|
||||||
|
{handleOnClose ? (
|
||||||
|
<IconButton onClick={handleOnClose}>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
) : null}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<ResetPasswordForm onSubmit={onSubmit}></ResetPasswordForm>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ResetPasswordDialog;
|
|
@ -20,3 +20,5 @@ export { default as ModGuard } from './Guard/ModGuard';
|
||||||
|
|
||||||
// Dialogs
|
// Dialogs
|
||||||
export { default as CardImportDialog } from './CardImportDialog/CardImportDialog';
|
export { default as CardImportDialog } from './CardImportDialog/CardImportDialog';
|
||||||
|
export { default as RequestPasswordResetDialog } from './RequestPasswordResetDialog/RequestPasswordResetDialog';
|
||||||
|
export { default as ResetPasswordDialog } from './ResetPasswordDialog/ResetPasswordDialog';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Redirect } from 'react-router-dom';
|
import { Redirect } from 'react-router-dom';
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
|
@ -7,11 +7,14 @@ import Button from '@material-ui/core/Button';
|
||||||
import Paper from '@material-ui/core/Paper';
|
import Paper from '@material-ui/core/Paper';
|
||||||
import Typography from '@material-ui/core/Typography';
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
|
|
||||||
import { AuthenticationService } from 'api';
|
import { AuthenticationService } from 'api';
|
||||||
|
import { RequestPasswordResetDialog, ResetPasswordDialog } from 'components';
|
||||||
import { LoginForm } from 'forms';
|
import { LoginForm } from 'forms';
|
||||||
|
import { useReduxEffect } from 'hooks';
|
||||||
import { Images } from 'images';
|
import { Images } from 'images';
|
||||||
import { RouteEnum } from 'types';
|
import { RouteEnum } from 'types';
|
||||||
import { ServerSelectors } from 'store';
|
import { ServerSelectors, ServerTypes } from 'store';
|
||||||
|
|
||||||
import './Login.css';
|
import './Login.css';
|
||||||
|
|
||||||
|
@ -56,6 +59,15 @@ const Login = ({ state, description }: LoginProps) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const isConnected = AuthenticationService.isConnected(state);
|
const isConnected = AuthenticationService.isConnected(state);
|
||||||
|
|
||||||
|
const [dialogState, setDialogState] = useState({
|
||||||
|
openRequest: false,
|
||||||
|
openReset: false
|
||||||
|
});
|
||||||
|
|
||||||
|
useReduxEffect(() => {
|
||||||
|
openResetPasswordDialog();
|
||||||
|
}, ServerTypes.RESET_PASSWORD, []);
|
||||||
|
|
||||||
const showDescription = () => {
|
const showDescription = () => {
|
||||||
return !isConnected && description?.length;
|
return !isConnected && description?.length;
|
||||||
};
|
};
|
||||||
|
@ -64,6 +76,38 @@ const Login = ({ state, description }: LoginProps) => {
|
||||||
console.log('Login.createAccount->openForgotPasswordDialog');
|
console.log('Login.createAccount->openForgotPasswordDialog');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRequestPasswordResetDialogSubmit = async ({ user, email, host, port }) => {
|
||||||
|
if (email) {
|
||||||
|
AuthenticationService.resetPasswordChallenge({ user, email, host, port } as any);
|
||||||
|
} else {
|
||||||
|
AuthenticationService.resetPasswordRequest({ user, host, port } as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
closeRequestPasswordResetDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleResetPasswordDialogSubmit = async ({ user, token, newPassword, passwordAgain, host, port }) => {
|
||||||
|
AuthenticationService.resetPassword({ user, token, newPassword, host, port } as any);
|
||||||
|
|
||||||
|
closeResetPasswordDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeRequestPasswordResetDialog = () => {
|
||||||
|
setDialogState(s => ({ ...s, openRequest: false }));
|
||||||
|
}
|
||||||
|
|
||||||
|
const openRequestPasswordResetDialog = () => {
|
||||||
|
setDialogState(s => ({ ...s, openRequest: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeResetPasswordDialog = () => {
|
||||||
|
setDialogState(s => ({ ...s, openReset: false }));
|
||||||
|
}
|
||||||
|
|
||||||
|
const openResetPasswordDialog = () => {
|
||||||
|
setDialogState(s => ({ ...s, openReset: 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} />}
|
||||||
|
@ -138,6 +182,18 @@ const Login = ({ state, description }: LoginProps) => {
|
||||||
</div>
|
</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<RequestPasswordResetDialog
|
||||||
|
isOpen={dialogState.openRequest}
|
||||||
|
onSubmit={handleRequestPasswordResetDialogSubmit}
|
||||||
|
handleClose={closeRequestPasswordResetDialog}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ResetPasswordDialog
|
||||||
|
isOpen={dialogState.openReset}
|
||||||
|
onSubmit={handleResetPasswordDialogSubmit}
|
||||||
|
handleClose={closeResetPasswordDialog}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
.RequestPasswordResetForm {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RequestPasswordResetForm-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RequestPasswordResetForm-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: -20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RequestPasswordResetForm-submit {
|
||||||
|
width: 100%;
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
// eslint-disable-next-line
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { Form, Field, reduxForm, change } from 'redux-form'
|
||||||
|
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
|
||||||
|
import { InputField, KnownHosts } from 'components';
|
||||||
|
import { FormKey } from 'types';
|
||||||
|
|
||||||
|
import './RequestPasswordResetForm.css';
|
||||||
|
|
||||||
|
const RequestPasswordResetForm = (props) => {
|
||||||
|
const { dispatch, handleSubmit } = props;
|
||||||
|
|
||||||
|
const onHostChange = ({ host, port }) => {
|
||||||
|
dispatch(change(FormKey.RESET_PASSWORD_REQUEST, 'host', host));
|
||||||
|
dispatch(change(FormKey.RESET_PASSWORD_REQUEST, 'port', port));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form className="RequestPasswordResetForm" onSubmit={handleSubmit}>
|
||||||
|
<div className="RequestPasswordResetForm-items">
|
||||||
|
<div className="RequestPasswordResetForm-item">
|
||||||
|
<Field label="Username" name="user" component={InputField} autoComplete="username" />
|
||||||
|
</div>
|
||||||
|
<div className="RequestPasswordResetForm-item">
|
||||||
|
<KnownHosts onChange={onHostChange} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button className="RequestPasswordResetForm-submit rounded tall" color="primary" variant="contained" type="submit">
|
||||||
|
Request Reset Token
|
||||||
|
</Button>
|
||||||
|
</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));
|
20
webclient/src/forms/ResetPasswordForm/ResetPasswordForm.css
Normal file
20
webclient/src/forms/ResetPasswordForm/ResetPasswordForm.css
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
.ResetPasswordForm {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ResetPasswordForm-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ResetPasswordForm-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: -20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ResetPasswordForm-submit {
|
||||||
|
width: 100%;
|
||||||
|
}
|
86
webclient/src/forms/ResetPasswordForm/ResetPasswordForm.tsx
Normal file
86
webclient/src/forms/ResetPasswordForm/ResetPasswordForm.tsx
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
// eslint-disable-next-line
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { Form, Field, reduxForm, change } from 'redux-form'
|
||||||
|
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
|
||||||
|
import { InputField, KnownHosts } from 'components';
|
||||||
|
import { FormKey } from 'types';
|
||||||
|
|
||||||
|
import './ResetPasswordForm.css';
|
||||||
|
|
||||||
|
const ResetPasswordForm = (props) => {
|
||||||
|
const { dispatch, handleSubmit } = props;
|
||||||
|
|
||||||
|
const onHostChange = ({ host, port }) => {
|
||||||
|
dispatch(change(FormKey.RESET_PASSWORD, 'host', host));
|
||||||
|
dispatch(change(FormKey.RESET_PASSWORD, 'port', port));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form className="ResetPasswordForm" onSubmit={handleSubmit}>
|
||||||
|
<div className="ResetPasswordForm-items">
|
||||||
|
<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">
|
||||||
|
<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 = {};
|
||||||
|
|
||||||
|
if (!values.user) {
|
||||||
|
errors.user = 'Required';
|
||||||
|
}
|
||||||
|
if (!values.token) {
|
||||||
|
errors.token = 'Required';
|
||||||
|
}
|
||||||
|
if (!values.newPassword) {
|
||||||
|
errors.newPassword = 'Required';
|
||||||
|
}
|
||||||
|
if (!values.passwordAgain) {
|
||||||
|
errors.passwordAgain = 'Required';
|
||||||
|
} else if (values.newPassword !== values.passwordAgain) {
|
||||||
|
errors.passwordAgain = 'Passwords don\'t match'
|
||||||
|
}
|
||||||
|
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)(ResetPasswordForm));
|
|
@ -3,3 +3,5 @@ export { default as ConnectForm } from './ConnectForm/ConnectForm';
|
||||||
export { default as LoginForm } from './LoginForm/LoginForm';
|
export { default as LoginForm } from './LoginForm/LoginForm';
|
||||||
export { default as RegisterForm } from './RegisterForm/RegisterForm';
|
export { default as RegisterForm } from './RegisterForm/RegisterForm';
|
||||||
export { default as SearchForm } from './SearchForm/SearchForm';
|
export { default as SearchForm } from './SearchForm/SearchForm';
|
||||||
|
export { default as RequestPasswordResetForm } from './RequestPasswordResetForm/RequestPasswordResetForm';
|
||||||
|
export { default as ResetPasswordForm } from './ResetPasswordForm/ResetPasswordForm';
|
||||||
|
|
1
webclient/src/hooks/index.ts
Normal file
1
webclient/src/hooks/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from './useReduxEffect';
|
47
webclient/src/hooks/useReduxEffect.tsx
Normal file
47
webclient/src/hooks/useReduxEffect.tsx
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
File is adapted from https://github.com/Qeepsake/use-redux-effect under MIT License
|
||||||
|
* @author Aspect Apps Limited
|
||||||
|
* @description
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useRef, useEffect, DependencyList } from 'react'
|
||||||
|
import { useStore } from 'react-redux'
|
||||||
|
import { castArray } from 'lodash'
|
||||||
|
import { AnyAction } from 'redux'
|
||||||
|
|
||||||
|
export type ReduxEffect = (action: AnyAction) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribes to redux store events
|
||||||
|
*
|
||||||
|
* @param effect
|
||||||
|
* @param type
|
||||||
|
* @param deps
|
||||||
|
*/
|
||||||
|
export function useReduxEffect(
|
||||||
|
effect: ReduxEffect,
|
||||||
|
type: string | string[],
|
||||||
|
deps: DependencyList = [],
|
||||||
|
): void {
|
||||||
|
const currentValue = useRef(null)
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
|
const handleChange = (): void => {
|
||||||
|
const state = store.getState()
|
||||||
|
const action = state.action
|
||||||
|
const previousValue = currentValue.current
|
||||||
|
currentValue.current = action.count
|
||||||
|
|
||||||
|
if (
|
||||||
|
previousValue !== action.count &&
|
||||||
|
castArray(type).includes(action.type)
|
||||||
|
) {
|
||||||
|
effect(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = store.subscribe(handleChange)
|
||||||
|
return (): void => unsubscribe()
|
||||||
|
}, deps)
|
||||||
|
}
|
43
webclient/src/store/actions/actionReducer.ts
Normal file
43
webclient/src/store/actions/actionReducer.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* @author Luke Brandon Farrell
|
||||||
|
* @description Application reducer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AnyAction } from 'redux'
|
||||||
|
|
||||||
|
interface InitialState {
|
||||||
|
type: string | null
|
||||||
|
payload: any
|
||||||
|
meta: any
|
||||||
|
error: boolean
|
||||||
|
count: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial data.
|
||||||
|
*/
|
||||||
|
const initialState: InitialState = {
|
||||||
|
type: null,
|
||||||
|
payload: null,
|
||||||
|
meta: null,
|
||||||
|
error: false,
|
||||||
|
count: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the application state.
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* @param action
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
export const actionReducer = (
|
||||||
|
state = initialState,
|
||||||
|
action: AnyAction,
|
||||||
|
): InitialState => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...action,
|
||||||
|
count: state.count + 1,
|
||||||
|
}
|
||||||
|
}
|
1
webclient/src/store/actions/index.ts
Normal file
1
webclient/src/store/actions/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export { actionReducer } from './actionReducer';
|
|
@ -6,6 +6,7 @@ export { SortUtil } from './common';
|
||||||
// Server
|
// Server
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
Types as ServerTypes,
|
||||||
Selectors as ServerSelectors,
|
Selectors as ServerSelectors,
|
||||||
Dispatch as ServerDispatch } from './server';
|
Dispatch as ServerDispatch } from './server';
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,12 @@ import { combineReducers } from 'redux';
|
||||||
import { roomsReducer } from './rooms';
|
import { roomsReducer } from './rooms';
|
||||||
import { serverReducer } from './server';
|
import { serverReducer } from './server';
|
||||||
import { reducer as formReducer } from 'redux-form'
|
import { reducer as formReducer } from 'redux-form'
|
||||||
|
import { actionReducer } from './actions'
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
rooms: roomsReducer,
|
rooms: roomsReducer,
|
||||||
server: serverReducer,
|
server: serverReducer,
|
||||||
|
|
||||||
form: formReducer
|
form: formReducer,
|
||||||
|
action: actionReducer
|
||||||
});
|
});
|
||||||
|
|
|
@ -66,5 +66,8 @@ export const Actions = {
|
||||||
}),
|
}),
|
||||||
clearLogs: () => ({
|
clearLogs: () => ({
|
||||||
type: Types.CLEAR_LOGS
|
type: Types.CLEAR_LOGS
|
||||||
|
}),
|
||||||
|
resetPassword: () => ({
|
||||||
|
type: Types.RESET_PASSWORD
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,5 +61,8 @@ export const Dispatch = {
|
||||||
},
|
},
|
||||||
serverMessage: message => {
|
serverMessage: message => {
|
||||||
store.dispatch(Actions.serverMessage(message));
|
store.dispatch(Actions.serverMessage(message));
|
||||||
|
},
|
||||||
|
resetPassword: () => {
|
||||||
|
store.dispatch(Actions.resetPassword());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,5 +15,6 @@ export const Types = {
|
||||||
USER_JOINED: '[Server] User Joined',
|
USER_JOINED: '[Server] User Joined',
|
||||||
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',
|
||||||
|
RESET_PASSWORD: '[Server] Reset Password'
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,8 @@ export enum FormKey {
|
||||||
CARD_IMPORT = 'CARD_IMPORT',
|
CARD_IMPORT = 'CARD_IMPORT',
|
||||||
CONNECT = 'CONNECT',
|
CONNECT = 'CONNECT',
|
||||||
LOGIN = 'LOGIN',
|
LOGIN = 'LOGIN',
|
||||||
|
RESET_PASSWORD_REQUEST = 'RESET_PASSWORD_REQUEST',
|
||||||
|
RESET_PASSWORD = 'RESET_PASSWORD',
|
||||||
REGISTER = 'REGISTER',
|
REGISTER = 'REGISTER',
|
||||||
SEARCH_LOGS = 'SEARCH_LOGS',
|
SEARCH_LOGS = 'SEARCH_LOGS',
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,8 @@ export class WebClient {
|
||||||
port: '',
|
port: '',
|
||||||
user: '',
|
user: '',
|
||||||
pass: '',
|
pass: '',
|
||||||
|
newPassword: '',
|
||||||
|
email: '',
|
||||||
clientid: null,
|
clientid: null,
|
||||||
reason: null,
|
reason: null,
|
||||||
autojoinrooms: true,
|
autojoinrooms: true,
|
||||||
|
|
|
@ -114,7 +114,6 @@ function removeFromList({ listName, userName }: RemoveFromListData) {
|
||||||
|
|
||||||
function serverIdentification(info: ServerIdentificationData) {
|
function serverIdentification(info: ServerIdentificationData) {
|
||||||
const { serverName, serverVersion, protocolVersion, serverOptions } = info;
|
const { serverName, serverVersion, protocolVersion, serverOptions } = info;
|
||||||
|
|
||||||
if (protocolVersion !== webClient.protocolVersion) {
|
if (protocolVersion !== webClient.protocolVersion) {
|
||||||
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, `Protocol version mismatch: ${protocolVersion}`);
|
SessionCommands.updateStatus(StatusEnum.DISCONNECTED, `Protocol version mismatch: ${protocolVersion}`);
|
||||||
SessionCommands.disconnect();
|
SessionCommands.disconnect();
|
||||||
|
|
|
@ -86,8 +86,7 @@ export class SessionPersistence {
|
||||||
}
|
}
|
||||||
|
|
||||||
static resetPassword() {
|
static resetPassword() {
|
||||||
console.log('Open Modal asking for reset token & new password');
|
ServerDispatch.resetPassword();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static resetPasswordSuccess() {
|
static resetPasswordSuccess() {
|
||||||
|
|
|
@ -10,6 +10,8 @@ export interface WebSocketOptions {
|
||||||
port: string;
|
port: string;
|
||||||
user: string;
|
user: string;
|
||||||
pass: string;
|
pass: string;
|
||||||
|
newPassword: string;
|
||||||
|
email: string;
|
||||||
autojoinrooms: boolean;
|
autojoinrooms: boolean;
|
||||||
keepalive: number;
|
keepalive: number;
|
||||||
clientid: string;
|
clientid: string;
|
||||||
|
|
Loading…
Reference in a new issue