DocSpace-buildtools/web/ASC.Web.Login/src/Login.jsx
Artem Tarasov 69ed46e8ae Merge branch 'feature/workspaces' of github.com:ONLYOFFICE/AppServer into feature/workspaces
# Conflicts:
#	products/ASC.People/Client/src/components/Article/Body/index.js
#	web/ASC.Web.Login/src/Login.jsx
2021-02-25 15:27:36 +03:00

485 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { Component, useEffect } from "react";
import styled, { css } from "styled-components";
import { withTranslation } from "react-i18next";
import PropTypes from "prop-types";
import { withRouter } from "react-router";
import Box from "@appserver/components/box";
import Button from "@appserver/components/button";
import Text from "@appserver/components/text";
import TextInput from "@appserver/components/text-input";
import Link from "@appserver/components/link";
import toastr from "@appserver/components/toast/toastr";
import Checkbox from "@appserver/components/checkbox";
//import HelpButton from "@appserver/components/help-button";
import PasswordInput from "@appserver/components/password-input";
import FieldContainer from "@appserver/components/field-container";
import PageLayout from "@appserver/common/PageLayout";
import ForgotPasswordModalDialog from "./sub-components/forgot-password-modal-dialog";
import Register from "./sub-components/register-container";
import { checkPwd } from "@appserver/common/desktop";
import { sendInstructionsToChangePassword } from "@appserver/common/api/people";
import { createPasswordHash, tryRedirectTo } from "@appserver/common/utils";
import { inject, observer } from "mobx-react";
import "./i18n";
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 {
display: flex;
.login-checkbox {
float: left;
span {
font-size: 12px;
}
}
}
.login-link {
line-height: 18px;
margin-left: auto;
}
}
.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;
}
}
`;
const LoginFormWrapper = styled.div`
display: grid;
grid-template-rows: ${(props) =>
props.enabledJoin
? props.isDesktop
? css`1fr 10px`
: css`1fr 66px`
: css`1fr`};
width: 100%;
height: calc(100vh-56px);
`;
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, hashSettings, isDesktop, defaultPage } = 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);
isDesktop && checkPwd();
login(userName, hash)
.then(() => tryRedirectTo(defaultPage))
.catch((error) => {
this.setState({
errorText: error,
identifierValid: !error,
passwordValid: !error,
isLoading: false,
});
});
};
componentDidMount() {
const { match, t, 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);
}
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={errorText ? errorText : t("RequiredFieldMessage")} //TODO: Add wrong login server error
>
<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={errorText ? "" : t("RequiredFieldMessage")} //TODO: Add wrong password server error
>
<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>
}
/>*/}
<Link
fontSize="13px"
color="#316DAA"
className="login-link"
type="page"
isHovered={false}
onClick={this.onClick}
>
{t("ForgotPassword")}
</Link>
</div>
</div>
{openDialog && (
<ForgotPasswordModalDialog
openDialog={openDialog}
isLoading={isLoading}
email={email}
emailError={emailError}
onChangeEmail={this.onChangeEmail}
onSendPasswordInstructions={this.onSendPasswordInstructions}
onDialogClose={this.onDialogClose}
t={t}
/>
)}
<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>
)}
{/* TODO: old error indication
<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,
hashSettings: PropTypes.object,
greetingTitle: PropTypes.string.isRequired,
t: PropTypes.func.isRequired,
socialButtons: PropTypes.array,
organizationName: PropTypes.string,
homepage: PropTypes.string,
defaultPage: PropTypes.string,
isDesktop: PropTypes.bool,
};
Form.defaultProps = {
identifier: "",
password: "",
email: "",
};
const FormWrapper = withTranslation()(Form);
//const RegisterWrapper = withTranslation()(Register);
const LoginForm = (props) => {
const { enabledJoin, isDesktop } = props;
return (
<LoginFormWrapper enabledJoin={enabledJoin} isDesktop={isDesktop}>
<PageLayout>
<PageLayout.SectionBody>
<FormWrapper {...props} />
</PageLayout.SectionBody>
</PageLayout>
<Register />
</LoginFormWrapper>
);
};
LoginForm.propTypes = {
isLoaded: PropTypes.bool,
enabledJoin: PropTypes.bool,
isDesktop: PropTypes.bool.isRequired,
};
export default inject(({ auth }) => {
const { settingsStore, isAuthenticated, isLoaded, login } = auth;
const {
greetingSettings: greetingTitle,
organizationName,
hashSettings,
enabledJoin,
defaultPage,
isDesktopClient: isDesktop,
} = settingsStore;
return {
isAuthenticated,
isLoaded,
organizationName,
greetingTitle,
hashSettings,
enabledJoin,
defaultPage,
isDesktop,
login,
};
})(withRouter(observer(LoginForm)));