Enhances password-recovery to show a logo if required, and adds password recovery to admin panel

This commit is contained in:
Maxi Redigonda 2018-07-26 17:46:26 -03:00
parent 949334fa71
commit 876fd8d52f
5 changed files with 176 additions and 36 deletions

View File

@ -2,24 +2,32 @@ 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
onBackToLoginClick: React.PropTypes.func,
renderLogo: React.PropTypes.bool
};
static defaultProps = {
renderLogo: false
};
render() {
return (
<Widget {...this.props} title={i18n('RECOVER_PASSWORD')}>
<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/>
@ -36,6 +44,16 @@ class PasswordRecovery extends React.Component {
);
}
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;

View File

@ -6,6 +6,11 @@
text-align: left;
}
&__content {
margin: 0 auto;
padding: 40px;
}
&__forgot-password {
margin-top: 20px;
}
@ -13,4 +18,9 @@
&__message {
margin-top: 18px;
}
&__image {
width: 365px;
margin-bottom: 30px;
}
}

View File

@ -1,11 +1,13 @@
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';
@ -17,31 +19,45 @@ import WidgetTransition from 'core-components/widget-transition';
class AdminLoginPage extends React.Component {
state = {
sideToShow: 'front'
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 (
<WidgetTransition sideToShow={this.state.sideToShow}>
{this.renderLogin()}
{this.renderPasswordRecovery()}
</WidgetTransition>
)
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 className="admin-login-page">
<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>
@ -49,48 +65,139 @@ class AdminLoginPage extends React.Component {
</div>
);
}
renderPasswordRecovery() {
return (
<div className="admin-login-page">
<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}>
<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()}
</Widget>
<div>
<PasswordRecovery recoverSent={this.state.recoverSent} formProps={this.getRecoverFormProps()} onBackToLoginClick={this.onBackToLoginClick.bind(this)} renderLogo={true}/>
</div>
);
}
onForgotPasswordClick() {
this.setState({sideToShow: 'back'});
renderRecoverStatus() {
let status = null;
if (this.state.recoverSent) {
status = (
<Message className="admin-login-page__message" type="info" leftAligned>
{i18n('RECOVER_SENT')}
</Message>
);
}
return status;
}
renderMessage() {
let message = null;
renderErrorStatus() {
let status = null;
if(this.props.session.failed) {
message = (
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) => {

View File

@ -2,6 +2,12 @@
.admin-login-page {
display: flex;
margin: 0 auto;
width: 446px;
&__container {
height: 361px;
}
&__content {
margin: 0 auto;
@ -21,4 +27,4 @@
&__error {
margin-top: 30px;
}
}
}

View File

@ -23,7 +23,6 @@ class WidgetTransition extends React.Component {
componentDidUpdate(prevProps) {
if (prevProps.sideToShow != this.props.sideToShow && this.primaryWidget && this.secondaryWidget) {
console.log("The component was updated!");
this.moveFocusToCurrentSide();
}
}