2020-11-24 10:20:14 +00:00
|
|
|
|
import React, { Component, useEffect } from "react";
|
2020-11-26 16:41:43 +00:00
|
|
|
|
import { connect } from "react-redux";
|
|
|
|
|
import styled from "styled-components";
|
|
|
|
|
import { withTranslation } from "react-i18next";
|
2020-11-24 10:20:14 +00:00
|
|
|
|
import PropTypes from "prop-types";
|
|
|
|
|
//import { withRouter } from "react-router";
|
|
|
|
|
import Box from "@appserver/components/src/components/box";
|
|
|
|
|
import Button from "@appserver/components/src/components/button";
|
|
|
|
|
import Text from "@appserver/components/src/components/text";
|
|
|
|
|
import TextInput from "@appserver/components/src/components/text-input";
|
|
|
|
|
import Link from "@appserver/components/src/components/link";
|
2020-11-26 16:41:43 +00:00
|
|
|
|
import toastr from "@appserver/components/src/components/toast/toastr";
|
2020-11-24 10:20:14 +00:00
|
|
|
|
import Checkbox from "@appserver/components/src/components/checkbox";
|
|
|
|
|
import HelpButton from "@appserver/components/src/components/help-button";
|
|
|
|
|
import PasswordInput from "@appserver/components/src/components/password-input";
|
|
|
|
|
import FieldContainer from "@appserver/components/src/components/field-container";
|
2020-11-26 16:41:43 +00:00
|
|
|
|
import PageLayout from "@appserver/common/src/components/PageLayout";
|
2020-11-24 10:20:14 +00:00
|
|
|
|
|
|
|
|
|
import i18n from "./i18n";
|
2020-11-26 16:41:43 +00:00
|
|
|
|
import ForgotPasswordModalDialog from "./sub-components/forgot-password-modal-dialog";
|
|
|
|
|
import Register from "./sub-components/register-container";
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
login,
|
|
|
|
|
setIsLoaded,
|
|
|
|
|
reloadPortalSettings,
|
|
|
|
|
} from "@appserver/common/src/store/auth/actions";
|
|
|
|
|
|
|
|
|
|
import { getLanguage } from "@appserver/common/src/store/auth/selectors";
|
|
|
|
|
import { sendInstructionsToChangePassword } from "@appserver/common/src/api/people";
|
|
|
|
|
import {
|
|
|
|
|
createPasswordHash,
|
|
|
|
|
redirectToDefaultPage,
|
|
|
|
|
} from "@appserver/common/src/utils";
|
2020-11-24 10:20:14 +00:00
|
|
|
|
|
|
|
|
|
const LoginContainer = styled.div`
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin: 120px auto 0 auto;
|
|
|
|
|
max-width: 960px;
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
padding: 0 16px;
|
|
|
|
|
max-width: 475px;
|
|
|
|
|
}
|
|
|
|
|
@media (max-width: 375px) {
|
|
|
|
|
margin: 72px auto 0 auto;
|
|
|
|
|
max-width: 311px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.greeting-title {
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
text-align: left;
|
|
|
|
|
}
|
|
|
|
|
@media (max-width: 375px) {
|
|
|
|
|
font-size: 23px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.auth-form-container {
|
|
|
|
|
margin: 32px 213px 0 213px;
|
|
|
|
|
width: 311px;
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
margin: 32px 0 0 0;
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
@media (max-width: 375px) {
|
|
|
|
|
margin: 32px 0 0 0;
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.login-forgot-wrapper {
|
|
|
|
|
height: 36px;
|
|
|
|
|
padding: 14px 0;
|
|
|
|
|
|
|
|
|
|
.login-checkbox-wrapper {
|
|
|
|
|
position: absolute;
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
|
|
|
|
.login-checkbox {
|
|
|
|
|
float: left;
|
|
|
|
|
span {
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.login-tooltip {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
|
|
|
|
@media (min-width: 1025px) {
|
|
|
|
|
margin-left: 8px;
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
}
|
|
|
|
|
@media (max-width: 1024px) {
|
|
|
|
|
padding: 4px 8px 8px 8px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.login-link {
|
|
|
|
|
float: right;
|
|
|
|
|
line-height: 16px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.login-button {
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.login-button-dialog {
|
|
|
|
|
margin-right: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.login-bottom-border {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 1px;
|
|
|
|
|
background: #eceef1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.login-bottom-text {
|
|
|
|
|
margin: 0 8px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
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: "",
|
|
|
|
|
emailError: false,
|
|
|
|
|
errorText: "",
|
|
|
|
|
socialButtons: [],
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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: "" });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onChangeEmail = (event) => {
|
|
|
|
|
this.setState({ email: event.target.value, emailError: false });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onChangeCheckbox = () => this.setState({ isChecked: !this.state.isChecked });
|
|
|
|
|
|
|
|
|
|
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 = () => {
|
|
|
|
|
if (!this.state.email.trim()) {
|
|
|
|
|
this.setState({ emailError: true });
|
|
|
|
|
} else {
|
|
|
|
|
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: "",
|
|
|
|
|
emailError: false,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onSubmit = () => {
|
|
|
|
|
const { errorText, identifier, password } = this.state;
|
|
|
|
|
const { login, setIsLoaded, history, hashSettings, homepage } = this.props;
|
|
|
|
|
|
|
|
|
|
errorText && this.setState({ errorText: "" });
|
|
|
|
|
let hasError = false;
|
|
|
|
|
|
|
|
|
|
const userName = identifier.trim();
|
|
|
|
|
|
|
|
|
|
if (!userName) {
|
|
|
|
|
hasError = true;
|
|
|
|
|
this.setState({ identifierValid: !hasError });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const pass = password.trim();
|
|
|
|
|
|
|
|
|
|
if (!pass) {
|
|
|
|
|
hasError = true;
|
|
|
|
|
this.setState({ passwordValid: !hasError });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hasError) return false;
|
|
|
|
|
|
|
|
|
|
this.setState({ isLoading: true });
|
|
|
|
|
const hash = createPasswordHash(pass, hashSettings);
|
|
|
|
|
|
|
|
|
|
login(userName, hash)
|
|
|
|
|
.then(() => {
|
|
|
|
|
if (!redirectToDefaultPage()) {
|
|
|
|
|
setIsLoaded(true);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
this.setState({ errorText: error, isLoading: false });
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
|
const {
|
|
|
|
|
match,
|
|
|
|
|
t,
|
|
|
|
|
hashSettings,
|
|
|
|
|
reloadPortalSettings,
|
|
|
|
|
organizationName,
|
|
|
|
|
} = this.props;
|
|
|
|
|
const { error, confirmedEmail } = {}; //match.params;
|
|
|
|
|
|
|
|
|
|
document.title = `${t("Authorization")} – ${organizationName}`; //TODO: implement the setDocumentTitle() utility in ASC.Web.Common
|
|
|
|
|
|
|
|
|
|
error && this.setState({ errorText: error });
|
|
|
|
|
confirmedEmail && this.setState({ identifier: confirmedEmail });
|
|
|
|
|
window.addEventListener("keyup", this.onKeyPress);
|
|
|
|
|
|
|
|
|
|
// if (!hashSettings) {
|
|
|
|
|
// reloadPortalSettings();
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
|
window.removeEventListener("keyup", this.onKeyPress);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
settings = {
|
|
|
|
|
minLength: 6,
|
|
|
|
|
upperCase: false,
|
|
|
|
|
digits: false,
|
|
|
|
|
specSymbols: false,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
const { greetingTitle, match, t } = this.props;
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
identifierValid,
|
|
|
|
|
identifier,
|
|
|
|
|
isLoading,
|
|
|
|
|
passwordValid,
|
|
|
|
|
password,
|
|
|
|
|
isChecked,
|
|
|
|
|
openDialog,
|
|
|
|
|
email,
|
|
|
|
|
emailError,
|
|
|
|
|
errorText,
|
|
|
|
|
socialButtons,
|
|
|
|
|
} = this.state;
|
|
|
|
|
const { confirmedEmail } = {}; //match.params;
|
|
|
|
|
|
|
|
|
|
//console.log("Login render");
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<LoginContainer>
|
|
|
|
|
<Text
|
|
|
|
|
fontSize="32px"
|
|
|
|
|
fontWeight={600}
|
|
|
|
|
textAlign="center"
|
|
|
|
|
className="greeting-title"
|
|
|
|
|
>
|
|
|
|
|
{greetingTitle}
|
|
|
|
|
</Text>
|
|
|
|
|
|
|
|
|
|
<form className="auth-form-container">
|
|
|
|
|
<FieldContainer
|
|
|
|
|
isVertical={true}
|
|
|
|
|
labelVisible={false}
|
|
|
|
|
hasError={!identifierValid}
|
|
|
|
|
errorMessage={t("RequiredFieldMessage")}
|
|
|
|
|
>
|
|
|
|
|
<TextInput
|
|
|
|
|
id="login"
|
|
|
|
|
name="login"
|
|
|
|
|
hasError={!identifierValid}
|
|
|
|
|
value={identifier}
|
|
|
|
|
placeholder={t("RegistrationEmailWatermark")}
|
|
|
|
|
size="large"
|
|
|
|
|
scale={true}
|
|
|
|
|
isAutoFocussed={true}
|
|
|
|
|
tabIndex={1}
|
|
|
|
|
isDisabled={isLoading}
|
|
|
|
|
autoComplete="username"
|
|
|
|
|
onChange={this.onChangeLogin}
|
|
|
|
|
onKeyDown={this.onKeyPress}
|
|
|
|
|
/>
|
|
|
|
|
</FieldContainer>
|
|
|
|
|
<FieldContainer
|
|
|
|
|
isVertical={true}
|
|
|
|
|
labelVisible={false}
|
|
|
|
|
hasError={!passwordValid}
|
|
|
|
|
errorMessage={t("RequiredFieldMessage")}
|
|
|
|
|
>
|
|
|
|
|
<PasswordInput
|
|
|
|
|
simpleView={true}
|
|
|
|
|
passwordSettings={this.settings}
|
|
|
|
|
id="password"
|
|
|
|
|
inputName="password"
|
|
|
|
|
placeholder={t("Password")}
|
|
|
|
|
type="password"
|
|
|
|
|
hasError={!passwordValid}
|
|
|
|
|
inputValue={password}
|
|
|
|
|
size="large"
|
|
|
|
|
scale={true}
|
|
|
|
|
tabIndex={1}
|
|
|
|
|
isDisabled={isLoading}
|
|
|
|
|
autoComplete="current-password"
|
|
|
|
|
onChange={this.onChangePassword}
|
|
|
|
|
onKeyDown={this.onKeyPress}
|
|
|
|
|
/>
|
|
|
|
|
</FieldContainer>
|
|
|
|
|
<div className="login-forgot-wrapper">
|
|
|
|
|
<div className="login-checkbox-wrapper">
|
|
|
|
|
<Checkbox
|
|
|
|
|
className="login-checkbox"
|
|
|
|
|
isChecked={isChecked}
|
|
|
|
|
onChange={this.onChangeCheckbox}
|
|
|
|
|
label={<Text fontSize="13px">{t("Remember")}</Text>}
|
|
|
|
|
/>
|
|
|
|
|
<HelpButton
|
|
|
|
|
className="login-tooltip"
|
|
|
|
|
helpButtonHeaderContent={t("CookieSettingsTitle")}
|
|
|
|
|
tooltipContent={
|
|
|
|
|
<Text fontSize="12px">{t("RememberHelper")}</Text>
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<Link
|
|
|
|
|
fontSize="13px"
|
|
|
|
|
color="#316DAA"
|
|
|
|
|
className="login-link"
|
|
|
|
|
type="page"
|
|
|
|
|
isHovered={false}
|
|
|
|
|
onClick={this.onClick}
|
|
|
|
|
>
|
|
|
|
|
{t("ForgotPassword")}
|
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
|
2020-11-26 16:41:43 +00:00
|
|
|
|
{openDialog && (
|
2020-11-24 10:20:14 +00:00
|
|
|
|
<ForgotPasswordModalDialog
|
|
|
|
|
openDialog={openDialog}
|
|
|
|
|
isLoading={isLoading}
|
|
|
|
|
email={email}
|
|
|
|
|
emailError={emailError}
|
|
|
|
|
onChangeEmail={this.onChangeEmail}
|
|
|
|
|
onSendPasswordInstructions={this.onSendPasswordInstructions}
|
|
|
|
|
onDialogClose={this.onDialogClose}
|
|
|
|
|
t={t}
|
|
|
|
|
/>
|
2020-11-26 16:41:43 +00:00
|
|
|
|
)}
|
2020-11-24 10:20:14 +00:00
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
id="button"
|
|
|
|
|
className="login-button"
|
|
|
|
|
primary
|
|
|
|
|
size="large"
|
|
|
|
|
scale={true}
|
|
|
|
|
label={isLoading ? t("LoadingProcessing") : t("LoginButton")}
|
|
|
|
|
tabIndex={1}
|
|
|
|
|
isDisabled={isLoading}
|
|
|
|
|
isLoading={isLoading}
|
|
|
|
|
onClick={this.onSubmit}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
{confirmedEmail && (
|
|
|
|
|
<Text isBold={true} fontSize="16px">
|
|
|
|
|
{t("MessageEmailConfirmed")} {t("MessageAuthorize")}
|
|
|
|
|
</Text>
|
|
|
|
|
)}
|
|
|
|
|
<Text fontSize="14px" color="#c30">
|
|
|
|
|
{errorText}
|
|
|
|
|
</Text>
|
|
|
|
|
|
|
|
|
|
{socialButtons.length ? (
|
|
|
|
|
<Box displayProp="flex" alignItems="center">
|
|
|
|
|
<div className="login-bottom-border"></div>
|
|
|
|
|
<Text className="login-bottom-text" color="#A3A9AE">
|
|
|
|
|
{t("Or")}
|
|
|
|
|
</Text>
|
|
|
|
|
<div className="login-bottom-border"></div>
|
|
|
|
|
</Box>
|
|
|
|
|
) : null}
|
|
|
|
|
</form>
|
|
|
|
|
</LoginContainer>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Form.propTypes = {
|
|
|
|
|
// login: PropTypes.func.isRequired,
|
|
|
|
|
// match: PropTypes.object.isRequired,
|
|
|
|
|
// //history: PropTypes.object.isRequired,
|
|
|
|
|
// setIsLoaded: PropTypes.func.isRequired,
|
|
|
|
|
// greetingTitle: PropTypes.string.isRequired,
|
|
|
|
|
// t: PropTypes.func.isRequired,
|
|
|
|
|
// i18n: PropTypes.object.isRequired,
|
|
|
|
|
// language: PropTypes.string.isRequired,
|
|
|
|
|
// socialButtons: PropTypes.array,
|
|
|
|
|
// organizationName: PropTypes.string,
|
|
|
|
|
// homepage: PropTypes.string,
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
Form.defaultProps = {
|
|
|
|
|
identifier: "",
|
|
|
|
|
password: "",
|
|
|
|
|
email: "",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const FormWrapper = withTranslation()(Form);
|
|
|
|
|
|
|
|
|
|
const LoginForm = (props) => <FormWrapper i18n={i18n} {...props} />;
|
|
|
|
|
|
|
|
|
|
export default LoginForm;
|
|
|
|
|
|
2020-11-26 16:41:43 +00:00
|
|
|
|
/*const RegisterWrapper = withTranslation()(Register);
|
|
|
|
|
|
|
|
|
|
const LoginForm = (props) => {
|
|
|
|
|
const { language, isLoaded, enabledJoin } = props;
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
i18n.changeLanguage(language);
|
|
|
|
|
}, [language]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
{isLoaded && (
|
|
|
|
|
<>
|
|
|
|
|
<PageLayout>
|
|
|
|
|
<PageLayout.SectionBody>
|
|
|
|
|
<>
|
|
|
|
|
<FormWrapper i18n={i18n} {...props} />
|
|
|
|
|
{enabledJoin && <RegisterWrapper i18n={i18n} {...props} />}
|
|
|
|
|
</>
|
|
|
|
|
</PageLayout.SectionBody>
|
|
|
|
|
</PageLayout>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
};
|
2020-11-24 10:20:14 +00:00
|
|
|
|
|
2020-11-26 16:41:43 +00:00
|
|
|
|
LoginForm.propTypes = {
|
|
|
|
|
language: PropTypes.string.isRequired,
|
|
|
|
|
isLoaded: PropTypes.bool,
|
|
|
|
|
enabledJoin: PropTypes.bool,
|
|
|
|
|
};
|
2020-11-24 10:20:14 +00:00
|
|
|
|
|
2020-11-26 16:41:43 +00:00
|
|
|
|
function mapStateToProps(state) {
|
|
|
|
|
const { isLoaded, settings } = state.auth;
|
|
|
|
|
const {
|
|
|
|
|
greetingSettings,
|
|
|
|
|
enabledJoin,
|
|
|
|
|
organizationName,
|
|
|
|
|
hashSettings,
|
|
|
|
|
} = settings;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
isLoaded,
|
|
|
|
|
enabledJoin,
|
|
|
|
|
organizationName,
|
|
|
|
|
language: getLanguage(state),
|
|
|
|
|
greetingTitle: greetingSettings,
|
|
|
|
|
hashSettings,
|
|
|
|
|
};
|
|
|
|
|
}
|
2020-11-24 10:20:14 +00:00
|
|
|
|
|
2020-11-26 16:41:43 +00:00
|
|
|
|
export default connect(mapStateToProps, {
|
|
|
|
|
login,
|
|
|
|
|
setIsLoaded,
|
|
|
|
|
reloadPortalSettings,
|
|
|
|
|
})(withRouter(LoginForm));*/
|