Merge pull request #257 from mredigonda/admin-recover-password-issue-161
Admin recover password issue 161
This commit is contained in:
commit
51b086d63e
|
@ -0,0 +1,72 @@
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
|
||||
import Form from 'core-components/form';
|
||||
import FormField from 'core-components/form-field';
|
||||
import Widget from 'core-components/widget';
|
||||
import Button from 'core-components/button';
|
||||
import SubmitButton from 'core-components/submit-button';
|
||||
import Message from 'core-components/message';
|
||||
|
||||
class PasswordRecovery extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
recoverSent: React.PropTypes.bool,
|
||||
formProps: React.PropTypes.object,
|
||||
onBackToLoginClick: React.PropTypes.func,
|
||||
renderLogo: React.PropTypes.bool
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
renderLogo: false
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Widget {...this.props} className="password-recovery__content">
|
||||
{this.renderLogo()}
|
||||
<Form {...this.props.formProps}>
|
||||
<div className="password-recovery__inputs">
|
||||
<FormField placeholder={i18n('EMAIL_LOWERCASE')} name="email" className="password-recovery__input" validation="EMAIL" required/>
|
||||
</div>
|
||||
<div className="password-recovery__submit-button">
|
||||
<SubmitButton type="primary">{i18n('RECOVER_PASSWORD')}</SubmitButton>
|
||||
</div>
|
||||
</Form>
|
||||
<Button className="password-recovery__forgot-password" type="link" onClick={this.props.onBackToLoginClick} onMouseDown={(event) => {event.preventDefault()}}>
|
||||
{i18n('BACK_LOGIN_FORM')}
|
||||
</Button>
|
||||
{this.renderRecoverStatus()}
|
||||
</Widget>
|
||||
);
|
||||
}
|
||||
|
||||
renderLogo() {
|
||||
let logo = null;
|
||||
|
||||
if (this.props.renderLogo) {
|
||||
logo = (<div className="password-recovery__image"><img width="100%" src={API.getURL() + '/images/logo.png'} alt="OpenSupports Login Panel"/></div>);
|
||||
}
|
||||
|
||||
return logo;
|
||||
}
|
||||
|
||||
renderRecoverStatus() {
|
||||
let status = null;
|
||||
|
||||
if (this.props.recoverSent) {
|
||||
status = (
|
||||
<Message className="password-recovery__message" type="info" leftAligned>
|
||||
{i18n('RECOVER_SENT')}
|
||||
</Message>
|
||||
);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
export default PasswordRecovery;
|
|
@ -0,0 +1,26 @@
|
|||
.password-recovery {
|
||||
|
||||
&__inputs {
|
||||
display: inline-block;
|
||||
margin: 0 auto 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__content {
|
||||
margin: 0 auto;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
&__forgot-password {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
&__message {
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
&__image {
|
||||
width: 365px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
}
|
|
@ -1,55 +1,203 @@
|
|||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
import SessionActions from 'actions/session-actions';
|
||||
|
||||
import PasswordRecovery from 'app-components/password-recovery.js';
|
||||
import Button from 'core-components/button';
|
||||
import Form from 'core-components/form';
|
||||
import FormField from 'core-components/form-field';
|
||||
import SubmitButton from 'core-components/submit-button';
|
||||
import Message from 'core-components/message';
|
||||
import Widget from 'core-components/widget';
|
||||
import WidgetTransition from 'core-components/widget-transition';
|
||||
|
||||
class AdminLoginPage extends React.Component {
|
||||
|
||||
state = {
|
||||
sideToShow: 'front',
|
||||
loginFormErrors: {},
|
||||
recoverFormErrors: {},
|
||||
recoverSent: false,
|
||||
loadingLogin: false,
|
||||
loadingRecover: false
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (!prevProps.session.failed && this.props.session.failed) {
|
||||
this.refs.loginForm.refs.password.focus();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="admin-login-page">
|
||||
<WidgetTransition sideToShow={this.state.sideToShow} className={classNames('admin-login-page__container', this.props.className)}>
|
||||
{this.renderLogin()}
|
||||
{this.renderPasswordRecovery()}
|
||||
</WidgetTransition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderLogin() {
|
||||
return (
|
||||
<div>
|
||||
<Widget className="admin-login-page__content">
|
||||
<div className="admin-login-page__image"><img width="100%" src={API.getURL() + '/images/logo.png'} alt="OpenSupports Admin Panel"/></div>
|
||||
<div className="admin-login-page__login-form">
|
||||
<Form onSubmit={this.onSubmit.bind(this)} loading={this.props.session.pending}>
|
||||
<Form onSubmit={this.onLoginFormSubmit.bind(this)} loading={this.props.session.pending}>
|
||||
<FormField name="email" label={i18n('EMAIL')} field="input" validation="EMAIL" fieldProps={{size:'large'}} required />
|
||||
<FormField name="password" label={i18n('PASSWORD')} field="input" fieldProps={{password:true, size:'large'}} />
|
||||
<SubmitButton>{i18n('LOG_IN')}</SubmitButton>
|
||||
</Form>
|
||||
</div>
|
||||
{this.renderMessage()}
|
||||
{this.renderRecoverStatus()}
|
||||
{this.renderErrorStatus()}
|
||||
<Button className="login-widget__forgot-password" type="link" onClick={this.onForgotPasswordClick.bind(this)} onMouseDown={(event) => {event.preventDefault()}}>
|
||||
{i18n('FORGOT_PASSWORD')}
|
||||
</Button>
|
||||
</Widget>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderMessage() {
|
||||
let message = null;
|
||||
renderPasswordRecovery() {
|
||||
return (
|
||||
<div>
|
||||
<PasswordRecovery recoverSent={this.state.recoverSent} formProps={this.getRecoverFormProps()} onBackToLoginClick={this.onBackToLoginClick.bind(this)} renderLogo={true}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if(this.props.session.failed) {
|
||||
message = (
|
||||
renderRecoverStatus() {
|
||||
let status = null;
|
||||
|
||||
if (this.state.recoverSent) {
|
||||
status = (
|
||||
<Message className="admin-login-page__message" type="info" leftAligned>
|
||||
{i18n('RECOVER_SENT')}
|
||||
</Message>
|
||||
);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
renderErrorStatus() {
|
||||
let status = null;
|
||||
|
||||
if (this.props.session.failed) {
|
||||
status = (
|
||||
<Message className="admin-login-page__error" type="error">
|
||||
{i18n('EMAIL_OR_PASSWORD')}
|
||||
</Message>
|
||||
);
|
||||
}
|
||||
|
||||
return message;
|
||||
return status;
|
||||
}
|
||||
|
||||
onSubmit(formState) {
|
||||
getLoginFormProps() {
|
||||
return {
|
||||
loading: this.props.session.pending,
|
||||
className: 'admin-login-page__form',
|
||||
ref: 'loginForm',
|
||||
onSubmit: this.onLoginFormSubmit.bind(this),
|
||||
errors: this.getLoginFormErrors(),
|
||||
onValidateErrors: this.onLoginFormErrorsValidation.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
getRecoverFormProps() {
|
||||
return {
|
||||
loading: this.state.loadingRecover,
|
||||
className: 'admin-login-page__form',
|
||||
ref: 'recoverForm',
|
||||
onSubmit: this.onForgotPasswordSubmit.bind(this),
|
||||
errors: this.state.recoverFormErrors,
|
||||
onValidateErrors: this.onRecoverFormErrorsValidation.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
getLoginFormErrors() {
|
||||
let errors = _.extend({}, this.state.loginFormErrors);
|
||||
|
||||
if (this.props.session.failed) {
|
||||
if (this.props.session.failMessage === 'INVALID_CREDENTIALS') {
|
||||
errors.password = i18n('ERROR_PASSWORD');
|
||||
} else if (this.props.session.failMessage === 'UNVERIFIED_USER') {
|
||||
errors.email = i18n('UNVERIFIED_EMAIL');
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
onLoginFormSubmit(formState) {
|
||||
this.props.dispatch(SessionActions.login(_.extend({}, formState, {
|
||||
staff: true
|
||||
})));
|
||||
}
|
||||
|
||||
onForgotPasswordSubmit(formState) {
|
||||
this.setState({
|
||||
loadingRecover: true,
|
||||
recoverSent: false
|
||||
});
|
||||
|
||||
API.call({
|
||||
path: '/user/send-recover-password',
|
||||
data: _.extend({}, formState, {staff: true})
|
||||
}).then(this.onRecoverPasswordSent.bind(this)).catch(this.onRecoverPasswordFail.bind(this));
|
||||
}
|
||||
|
||||
onLoginFormErrorsValidation(errors) {
|
||||
this.setState({
|
||||
loginFormErrors: errors
|
||||
});
|
||||
}
|
||||
|
||||
onRecoverFormErrorsValidation(errors) {
|
||||
this.setState({
|
||||
recoverFormErrors: errors
|
||||
});
|
||||
}
|
||||
|
||||
onForgotPasswordClick() {
|
||||
this.setState({
|
||||
sideToShow: 'back'
|
||||
});
|
||||
}
|
||||
|
||||
onBackToLoginClick() {
|
||||
this.setState({
|
||||
sideToShow: 'front',
|
||||
recoverSent: false
|
||||
});
|
||||
}
|
||||
|
||||
onRecoverPasswordSent() {
|
||||
this.setState({
|
||||
loadingRecover: false,
|
||||
recoverSent: true
|
||||
});
|
||||
}
|
||||
|
||||
onRecoverPasswordFail() {
|
||||
this.setState({
|
||||
loadingRecover: false,
|
||||
recoverFormErrors: {
|
||||
email: i18n('EMAIL_NOT_EXIST')
|
||||
}
|
||||
}, function () {
|
||||
this.refs.recoverForm.refs.email.focus();
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
export default connect((store) => {
|
||||
|
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
.admin-login-page {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
width: 446px;
|
||||
|
||||
&__container {
|
||||
height: 361px;
|
||||
}
|
||||
|
||||
&__content {
|
||||
margin: 0 auto;
|
||||
|
|
|
@ -9,6 +9,7 @@ import API from 'lib-app/api-call';
|
|||
import focus from 'lib-core/focus';
|
||||
import i18n from 'lib-app/i18n';
|
||||
|
||||
import PasswordRecovery from 'app-components/password-recovery.js';
|
||||
import SubmitButton from 'core-components/submit-button';
|
||||
import Button from 'core-components/button';
|
||||
import Form from 'core-components/form';
|
||||
|
@ -65,20 +66,7 @@ class MainHomePageLoginWidget extends React.Component {
|
|||
|
||||
renderPasswordRecovery() {
|
||||
return (
|
||||
<Widget className="main-home-page__widget login-widget_password" title={i18n('RECOVER_PASSWORD')} ref="recoverWidget">
|
||||
<Form {...this.getRecoverFormProps()}>
|
||||
<div className="login-widget__inputs">
|
||||
<FormField placeholder={i18n('EMAIL_LOWERCASE')} name="email" className="login-widget__input" validation="EMAIL" required/>
|
||||
</div>
|
||||
<div className="login-widget__submit-button">
|
||||
<SubmitButton type="primary">{i18n('RECOVER_PASSWORD')}</SubmitButton>
|
||||
</div>
|
||||
</Form>
|
||||
<Button className="login-widget__forgot-password" type="link" onClick={this.onBackToLoginClick.bind(this)} onMouseDown={(event) => {event.preventDefault()}}>
|
||||
{i18n('BACK_LOGIN_FORM')}
|
||||
</Button>
|
||||
{this.renderRecoverStatus()}
|
||||
</Widget>
|
||||
<PasswordRecovery recoverSent={this.state.recoverSent} formProps={this.getRecoverFormProps()} onBackToLoginClick={this.onBackToLoginClick.bind(this)}/>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -163,14 +151,14 @@ class MainHomePageLoginWidget extends React.Component {
|
|||
onForgotPasswordClick() {
|
||||
this.setState({
|
||||
sideToShow: 'back'
|
||||
}, this.moveFocusToCurrentSide);
|
||||
});
|
||||
}
|
||||
|
||||
onBackToLoginClick() {
|
||||
this.setState({
|
||||
sideToShow: 'front',
|
||||
recoverSent: false
|
||||
}, this.moveFocusToCurrentSide);
|
||||
});
|
||||
}
|
||||
|
||||
onRecoverPasswordSent() {
|
||||
|
@ -190,23 +178,6 @@ class MainHomePageLoginWidget extends React.Component {
|
|||
this.refs.recoverForm.refs.email.focus();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
moveFocusToCurrentSide() {
|
||||
let currentWidget;
|
||||
let previousWidget;
|
||||
|
||||
if (this.state.sideToShow === 'front') {
|
||||
currentWidget = ReactDOM.findDOMNode(this.refs.loginWidget);
|
||||
previousWidget = ReactDOM.findDOMNode(this.refs.recoverWidget);
|
||||
} else {
|
||||
currentWidget = ReactDOM.findDOMNode(this.refs.recoverWidget);
|
||||
previousWidget = ReactDOM.findDOMNode(this.refs.loginWidget);
|
||||
}
|
||||
|
||||
if (focus.isActiveElementInsideDOMTree(previousWidget)) {
|
||||
focus.focusFirstInput(currentWidget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import _ from 'lodash';
|
|||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
import history from 'lib-app/history';
|
||||
|
||||
import Widget from 'core-components/widget';
|
||||
import Form from 'core-components/form';
|
||||
|
@ -73,8 +74,8 @@ class MainRecoverPasswordPage extends React.Component {
|
|||
}).then(this.onPasswordRecovered.bind(this)).catch(this.onPasswordRecoverFail.bind(this));
|
||||
}
|
||||
|
||||
onPasswordRecovered() {
|
||||
setTimeout(() => {this.props.history.push('/')}, 2000);
|
||||
onPasswordRecovered(response) {
|
||||
setTimeout(() => {history.push(response.data.staff ? '/admin' : '/')}, 2000);
|
||||
this.setState({
|
||||
recoverStatus: 'valid',
|
||||
loading: false
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import classNames from 'classnames';
|
||||
import _ from 'lodash';
|
||||
import {Motion, spring} from 'react-motion';
|
||||
import focus from 'lib-core/focus';
|
||||
|
||||
class WidgetTransition extends React.Component {
|
||||
|
||||
|
@ -19,6 +21,12 @@ class WidgetTransition extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.sideToShow != this.props.sideToShow && this.primaryWidget && this.secondaryWidget) {
|
||||
this.moveFocusToCurrentSide();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Motion defaultStyle={this.getDefaultAnimation()} style={this.getAnimation()}>
|
||||
|
@ -30,7 +38,7 @@ class WidgetTransition extends React.Component {
|
|||
renderChildren(animation) {
|
||||
return (
|
||||
<div className={this.getClass()}>
|
||||
{React.Children.map(this.props.children, function (child, index) {
|
||||
{React.Children.map(this.props.children, (child, index) => {
|
||||
let modifiedChild;
|
||||
|
||||
if (index === 0) {
|
||||
|
@ -38,14 +46,16 @@ class WidgetTransition extends React.Component {
|
|||
className: child.props.className + ' widget-transition--widget',
|
||||
style: _.extend ({}, child.props.style, {
|
||||
transform: `rotateY(${(animation.rotateY) ? animation.rotateY: 0}deg)`
|
||||
})
|
||||
}),
|
||||
ref: (node) => this.primaryWidget = node
|
||||
});
|
||||
} else {
|
||||
modifiedChild = React.cloneElement(child, {
|
||||
className: child.props.className + ' widget-transition--widget',
|
||||
style: _.extend ({}, child.props.style, {
|
||||
transform: `rotateY(${-180 + animation.rotateY}deg)`
|
||||
})
|
||||
}),
|
||||
ref: (node) => this.secondaryWidget = node
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -69,6 +79,24 @@ class WidgetTransition extends React.Component {
|
|||
rotateY: (this.props.sideToShow === 'front') ? spring(0, [100, 20]) : spring(180, [100, 20])
|
||||
};
|
||||
}
|
||||
|
||||
moveFocusToCurrentSide() {
|
||||
let currentWidget;
|
||||
let previousWidget;
|
||||
|
||||
if (this.props.sideToShow === 'front') {
|
||||
currentWidget = this.primaryWidget;
|
||||
previousWidget = this.secondaryWidget;
|
||||
} else {
|
||||
currentWidget = this.secondaryWidget;
|
||||
previousWidget = this.primaryWidget;
|
||||
}
|
||||
|
||||
currentWidget = ReactDOM.findDOMNode(currentWidget);
|
||||
previousWidget = ReactDOM.findDOMNode(previousWidget);
|
||||
|
||||
focus.focusFirstInput(currentWidget);
|
||||
}
|
||||
}
|
||||
|
||||
export default WidgetTransition;
|
||||
|
|
|
@ -77,7 +77,9 @@ module.exports = [
|
|||
if (data.password.length > 6) {
|
||||
return {
|
||||
status: 'success',
|
||||
data: {}
|
||||
data: {
|
||||
staff: true
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue