2019-11-27 11:14:51 +00:00
|
|
|
import React, { Component } from "react";
|
2019-11-22 11:48:54 +00:00
|
|
|
import PropTypes from "prop-types";
|
|
|
|
import { withRouter } from "react-router";
|
|
|
|
import {
|
|
|
|
Button,
|
|
|
|
TextInput,
|
|
|
|
PageLayout,
|
|
|
|
Text,
|
|
|
|
Link,
|
|
|
|
toastr,
|
|
|
|
Checkbox,
|
|
|
|
HelpButton
|
|
|
|
} from "asc-web-components";
|
|
|
|
import { connect } from "react-redux";
|
|
|
|
import styled from "styled-components";
|
2019-11-27 11:14:51 +00:00
|
|
|
import { withTranslation, I18nextProvider } from "react-i18next";
|
2019-11-22 11:48:54 +00:00
|
|
|
import i18n from "./i18n";
|
|
|
|
import SubModalDialog from "./sub-components/modal-dialog";
|
2019-11-25 12:52:34 +00:00
|
|
|
import { login, setIsLoaded } from "../../store/auth/actions";
|
|
|
|
import { sendInstructionsToChangePassword } from "../../api/people";
|
2019-11-22 11:48:54 +00:00
|
|
|
|
2019-11-29 08:00:03 +00:00
|
|
|
const FormContainer = styled.form`
|
2019-11-28 06:31:45 +00:00
|
|
|
margin: 50px auto 0 auto;
|
|
|
|
max-width: 432px;
|
2019-11-22 11:48:54 +00:00
|
|
|
|
2019-11-28 06:31:45 +00:00
|
|
|
.login-header {
|
2019-11-29 08:00:03 +00:00
|
|
|
margin-bottom: 24px;
|
|
|
|
|
2019-11-28 06:31:45 +00:00
|
|
|
.login-logo {
|
|
|
|
max-width: 216px;
|
|
|
|
max-height: 35px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.login-title {
|
|
|
|
margin: 8px 0;
|
|
|
|
}
|
2019-11-22 11:48:54 +00:00
|
|
|
}
|
|
|
|
|
2019-11-28 06:31:45 +00:00
|
|
|
.login-input {
|
|
|
|
margin-bottom: 24px;
|
2019-11-22 11:48:54 +00:00
|
|
|
}
|
|
|
|
|
2019-11-29 08:00:03 +00:00
|
|
|
.login-forgot-wrapper {
|
|
|
|
height: 36px;
|
|
|
|
|
|
|
|
.login-checkbox-wrapper {
|
|
|
|
position: absolute;
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
|
|
.login-checkbox {
|
|
|
|
float: left;
|
|
|
|
span {
|
|
|
|
font-size: 12px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.login-tooltip {
|
|
|
|
margin-left: 3px;
|
|
|
|
display: inline-flex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.login-link {
|
|
|
|
float: right;
|
|
|
|
line-height: 16px;
|
2019-11-22 11:48:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-28 06:31:45 +00:00
|
|
|
.login-button {
|
|
|
|
margin-bottom: 16px;
|
2019-11-22 11:48:54 +00:00
|
|
|
}
|
|
|
|
|
2019-11-28 06:31:45 +00:00
|
|
|
.login-button-dialog {
|
|
|
|
margin-right: 8px;
|
2019-11-22 11:48:54 +00:00
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
class Form extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
identifierValid: true,
|
|
|
|
identifier: "",
|
|
|
|
isLoading: false,
|
|
|
|
isDisabled: false,
|
|
|
|
passwordValid: true,
|
|
|
|
password: "",
|
|
|
|
isChecked: false,
|
|
|
|
openDialog: false,
|
|
|
|
email: "",
|
|
|
|
errorText: ""
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
onChangeLogin = event => {
|
|
|
|
this.setState({ identifier: event.target.value });
|
|
|
|
!this.state.identifierValid && this.setState({ identifierValid: true });
|
|
|
|
this.state.errorText && this.setState({ errorText: "" });
|
|
|
|
};
|
|
|
|
|
|
|
|
onChangePassword = event => {
|
|
|
|
this.setState({ password: event.target.value });
|
|
|
|
!this.state.passwordValid && this.setState({ passwordValid: true });
|
|
|
|
this.state.errorText && this.setState({ errorText: "" });
|
2019-11-22 11:48:54 +00:00
|
|
|
};
|
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
onChangeEmail = event => {
|
|
|
|
this.setState({ email: event.target.value });
|
2019-11-22 11:48:54 +00:00
|
|
|
};
|
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
onChangeCheckbox = () => this.setState({ isChecked: !this.state.isChecked });
|
2019-11-22 11:48:54 +00:00
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
onClick = () => {
|
|
|
|
this.setState({
|
|
|
|
openDialog: true,
|
|
|
|
isDisabled: true,
|
|
|
|
email: this.state.identifier
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
onKeyPress = event => {
|
|
|
|
if (event.key === "Enter") {
|
|
|
|
!this.state.isDisabled
|
|
|
|
? this.onSubmit()
|
|
|
|
: this.onSendPasswordInstructions();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
onSendPasswordInstructions = () => {
|
|
|
|
this.setState({ isLoading: true });
|
|
|
|
sendInstructionsToChangePassword(this.state.email)
|
|
|
|
.then(
|
|
|
|
res => toastr.success(res),
|
|
|
|
message => toastr.error(message)
|
|
|
|
)
|
|
|
|
.finally(this.onDialogClose());
|
|
|
|
};
|
|
|
|
|
|
|
|
onDialogClose = () => {
|
|
|
|
this.setState({
|
|
|
|
openDialog: false,
|
|
|
|
isDisabled: false,
|
|
|
|
isLoading: false,
|
|
|
|
email: ""
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
onSubmit = () => {
|
|
|
|
const { errorText, identifier, password } = this.state;
|
|
|
|
const { login, setIsLoaded, history } = this.props;
|
|
|
|
|
|
|
|
errorText && this.setState({ errorText: "" });
|
2019-11-22 11:48:54 +00:00
|
|
|
let hasError = false;
|
|
|
|
|
|
|
|
const userName = identifier.trim();
|
|
|
|
|
|
|
|
if (!userName) {
|
|
|
|
hasError = true;
|
2019-11-27 11:14:51 +00:00
|
|
|
this.setState({ identifierValid: !hasError });
|
2019-11-22 11:48:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const pass = password.trim();
|
|
|
|
|
|
|
|
if (!pass) {
|
|
|
|
hasError = true;
|
2019-11-27 11:14:51 +00:00
|
|
|
this.setState({ passwordValid: !hasError });
|
2019-11-22 11:48:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hasError) return false;
|
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
this.setState({ isLoading: true });
|
2019-11-22 11:48:54 +00:00
|
|
|
|
2019-11-28 12:08:08 +00:00
|
|
|
login(userName, pass)
|
|
|
|
.then(() => {
|
2019-11-22 11:48:54 +00:00
|
|
|
setIsLoaded(true);
|
|
|
|
history.push("/");
|
2019-11-28 12:08:08 +00:00
|
|
|
})
|
|
|
|
.catch(error => {
|
2019-11-27 11:14:51 +00:00
|
|
|
this.setState({ errorText: error, isLoading: false });
|
2019-11-28 12:08:08 +00:00
|
|
|
});
|
2019-11-22 11:48:54 +00:00
|
|
|
};
|
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
componentDidMount() {
|
|
|
|
const { language, match } = this.props;
|
|
|
|
const { params } = match;
|
|
|
|
i18n.changeLanguage(language);
|
|
|
|
params.error && this.setState({ errorText: params.error });
|
|
|
|
window.addEventListener("keyup", this.onKeyPress);
|
|
|
|
}
|
2019-11-22 11:48:54 +00:00
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
componentWillUnmount() {
|
|
|
|
window.removeEventListener("keyup", this.onKeyPress);
|
|
|
|
}
|
2019-11-22 11:48:54 +00:00
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
render() {
|
|
|
|
const { greetingTitle, match, t } = this.props;
|
2019-11-28 06:31:45 +00:00
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
const {
|
|
|
|
identifierValid,
|
|
|
|
identifier,
|
|
|
|
isLoading,
|
|
|
|
passwordValid,
|
|
|
|
password,
|
|
|
|
isChecked,
|
|
|
|
openDialog,
|
|
|
|
email,
|
|
|
|
errorText
|
|
|
|
} = this.state;
|
|
|
|
const { params } = match;
|
|
|
|
|
|
|
|
//console.log("Login render");
|
|
|
|
|
|
|
|
return (
|
|
|
|
<FormContainer>
|
2019-11-28 06:31:45 +00:00
|
|
|
<div className="login-header">
|
|
|
|
<img
|
|
|
|
className="login-logo"
|
|
|
|
src="images/dark_general.png"
|
|
|
|
alt="Logo"
|
|
|
|
/>
|
2019-11-29 08:00:03 +00:00
|
|
|
<Text.Headline className="login-title" color="#116d9d">
|
|
|
|
{greetingTitle}
|
|
|
|
</Text.Headline>
|
2019-11-28 06:31:45 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<TextInput
|
|
|
|
id="login"
|
|
|
|
name="login"
|
|
|
|
hasError={!identifierValid}
|
|
|
|
value={identifier}
|
|
|
|
placeholder={t("RegistrationEmailWatermark")}
|
|
|
|
size="huge"
|
|
|
|
scale={true}
|
|
|
|
isAutoFocussed={true}
|
|
|
|
tabIndex={1}
|
|
|
|
isDisabled={isLoading}
|
|
|
|
autoComplete="username"
|
|
|
|
onChange={this.onChangeLogin}
|
|
|
|
onKeyDown={this.onKeyPress}
|
|
|
|
className="login-input"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<TextInput
|
|
|
|
id="password"
|
|
|
|
name="password"
|
|
|
|
type="password"
|
|
|
|
hasError={!passwordValid}
|
|
|
|
value={password}
|
|
|
|
placeholder={t("Password")}
|
|
|
|
size="huge"
|
|
|
|
scale={true}
|
|
|
|
isAutoFocussed={true}
|
|
|
|
tabIndex={2}
|
|
|
|
isDisabled={isLoading}
|
|
|
|
autoComplete="current-password"
|
|
|
|
onChange={this.onChangePassword}
|
|
|
|
onKeyDown={this.onKeyPress}
|
|
|
|
className="login-input"
|
|
|
|
/>
|
|
|
|
|
2019-11-29 08:00:03 +00:00
|
|
|
<div className="login-forgot-wrapper">
|
|
|
|
<div className="login-checkbox-wrapper">
|
2019-11-27 11:14:51 +00:00
|
|
|
<Checkbox
|
2019-11-28 06:31:45 +00:00
|
|
|
className="login-checkbox"
|
2019-11-27 11:14:51 +00:00
|
|
|
isChecked={isChecked}
|
|
|
|
onChange={this.onChangeCheckbox}
|
|
|
|
label={t("Remember")}
|
|
|
|
/>
|
2019-11-28 06:31:45 +00:00
|
|
|
<HelpButton
|
|
|
|
className="login-tooltip"
|
|
|
|
helpButtonHeaderContent={t("CookieSettingsTitle")}
|
|
|
|
tooltipContent={
|
|
|
|
<Text.Body fontSize={12}>{t("RememberHelper")}</Text.Body>
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<Link
|
|
|
|
fontSize={12}
|
|
|
|
className="login-link"
|
|
|
|
type="page"
|
|
|
|
isHovered={true}
|
|
|
|
onClick={this.onClick}
|
|
|
|
>
|
|
|
|
{t("ForgotPassword")}
|
|
|
|
</Link>
|
|
|
|
</div>
|
2019-11-27 11:14:51 +00:00
|
|
|
|
|
|
|
{openDialog ? (
|
|
|
|
<SubModalDialog
|
|
|
|
openDialog={openDialog}
|
|
|
|
isLoading={isLoading}
|
|
|
|
email={email}
|
|
|
|
onChangeEmail={this.onChangeEmail}
|
|
|
|
onSendPasswordInstructions={this.onSendPasswordInstructions}
|
|
|
|
onDialogClose={this.onDialogClose}
|
|
|
|
t={t}
|
|
|
|
/>
|
|
|
|
) : null}
|
|
|
|
|
2019-11-28 06:31:45 +00:00
|
|
|
<Button
|
2019-11-29 08:00:03 +00:00
|
|
|
id="button"
|
2019-11-28 06:31:45 +00:00
|
|
|
className="login-button"
|
|
|
|
primary
|
|
|
|
size="big"
|
|
|
|
label={isLoading ? t("LoadingProcessing") : t("LoginButton")}
|
|
|
|
tabIndex={3}
|
|
|
|
isDisabled={isLoading}
|
|
|
|
isLoading={isLoading}
|
|
|
|
onClick={this.onSubmit}
|
|
|
|
/>
|
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
{params.confirmedEmail && (
|
2019-11-28 06:31:45 +00:00
|
|
|
<Text.Body isBold={true} fontSize={16}>
|
|
|
|
{t("MessageEmailConfirmed")} {t("MessageAuthorize")}
|
|
|
|
</Text.Body>
|
2019-11-27 11:14:51 +00:00
|
|
|
)}
|
2019-11-29 08:00:03 +00:00
|
|
|
<Text.Body fontSize={14} color="#c30">
|
|
|
|
{errorText}
|
|
|
|
</Text.Body>
|
2019-11-27 11:14:51 +00:00
|
|
|
</FormContainer>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const FormWrapper = withTranslation()(Form);
|
|
|
|
|
|
|
|
const LoginForm = props => {
|
|
|
|
const { language } = props;
|
|
|
|
i18n.changeLanguage(language);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<I18nextProvider i18n={i18n}>
|
|
|
|
<PageLayout sectionBodyContent={<FormWrapper {...props} />} />
|
|
|
|
</I18nextProvider>
|
2019-11-22 11:48:54 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
Form.propTypes = {
|
2019-11-22 11:48:54 +00:00
|
|
|
login: PropTypes.func.isRequired,
|
|
|
|
match: PropTypes.object.isRequired,
|
2019-11-27 11:14:51 +00:00
|
|
|
history: PropTypes.object.isRequired,
|
|
|
|
setIsLoaded: PropTypes.func.isRequired,
|
|
|
|
greetingTitle: PropTypes.string.isRequired,
|
|
|
|
t: PropTypes.func.isRequired,
|
|
|
|
language: PropTypes.string.isRequired
|
2019-11-22 11:48:54 +00:00
|
|
|
};
|
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
Form.defaultProps = {
|
2019-11-22 11:48:54 +00:00
|
|
|
identifier: "",
|
|
|
|
password: "",
|
|
|
|
email: ""
|
|
|
|
};
|
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
LoginForm.propTypes = {
|
|
|
|
language: PropTypes.string.isRequired
|
|
|
|
};
|
|
|
|
|
2019-11-22 11:48:54 +00:00
|
|
|
function mapStateToProps(state) {
|
|
|
|
return {
|
|
|
|
language: state.auth.user.cultureName || state.auth.settings.culture,
|
|
|
|
greetingTitle: state.auth.settings.greetingSettings
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-11-27 11:14:51 +00:00
|
|
|
export default connect(mapStateToProps, { login, setIsLoaded })(
|
|
|
|
withRouter(LoginForm)
|
|
|
|
);
|