awx/src/screens/Login/Login.jsx
2019-06-21 12:01:29 -04:00

152 lines
4.3 KiB
JavaScript

import React, { Component } from 'react';
import { Redirect, withRouter } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import styled from 'styled-components';
import {
LoginForm,
LoginPage as PFLoginPage,
} from '@patternfly/react-core';
import { RootAPI } from '../../api';
import { BrandName } from '../../variables';
import brandLogo from '../../../images/brand-logo.svg';
const LoginPage = styled(PFLoginPage)`
& .pf-c-brand {
max-height: 285px;
}
`;
class AWXLogin extends Component {
constructor (props) {
super(props);
this.state = {
username: '',
password: '',
hasAuthError: false,
hasValidationError: false,
isAuthenticating: false,
isLoading: true,
logo: null,
loginInfo: null,
};
this.handleChangeUsername = this.handleChangeUsername.bind(this);
this.handleChangePassword = this.handleChangePassword.bind(this);
this.handleLoginButtonClick = this.handleLoginButtonClick.bind(this);
this.loadCustomLoginInfo = this.loadCustomLoginInfo.bind(this);
}
async componentDidMount () {
await this.loadCustomLoginInfo();
}
async loadCustomLoginInfo () {
this.setState({ isLoading: true });
try {
const { data: { custom_logo, custom_login_info } } = await RootAPI.read();
const logo = custom_logo ? `data:image/jpeg;${custom_logo}` : brandLogo;
this.setState({ logo, loginInfo: custom_login_info });
} catch (err) {
this.setState({ logo: brandLogo });
} finally {
this.setState({ isLoading: false });
}
}
async handleLoginButtonClick (event) {
const { username, password, isAuthenticating } = this.state;
event.preventDefault();
if (isAuthenticating) {
return;
}
this.setState({ hasAuthError: false, isAuthenticating: true });
try {
// note: if authentication is successful, the appropriate cookie will be set automatically
// and isAuthenticated() (the source of truth) will start returning true.
await RootAPI.login(username, password);
} catch (err) {
if (err && err.response && err.response.status === 401) {
this.setState({ hasValidationError: true });
} else {
this.setState({ hasAuthError: true });
}
} finally {
this.setState({ isAuthenticating: false });
}
}
handleChangeUsername (value) {
this.setState({ username: value, hasValidationError: false });
}
handleChangePassword (value) {
this.setState({ password: value, hasValidationError: false });
}
render () {
const {
hasAuthError,
hasValidationError,
username,
password,
isLoading,
logo,
loginInfo,
} = this.state;
const { alt, i18n, isAuthenticated } = this.props;
// Setting BrandName to a variable here is necessary to get the jest tests
// passing. Attempting to use BrandName in the template literal results
// in failing tests.
const brandName = BrandName;
if (isLoading) {
return null;
}
if (isAuthenticated(document.cookie)) {
return (<Redirect to="/" />);
}
let helperText;
if (hasValidationError) {
helperText = i18n._(t`Invalid username or password. Please try again.`);
} else {
helperText = i18n._(t`There was a problem signing in. Please try again.`);
}
return (
<LoginPage
brandImgSrc={logo}
brandImgAlt={alt || brandName}
loginTitle={i18n._(t`Welcome to Ansible ${brandName}! Please Sign In.`)}
textContent={loginInfo}
>
<LoginForm
className={(hasAuthError || hasValidationError) ? 'pf-m-error' : ''}
usernameLabel={i18n._(t`Username`)}
passwordLabel={i18n._(t`Password`)}
showHelperText={(hasAuthError || hasValidationError)}
helperText={helperText}
usernameValue={username}
passwordValue={password}
isValidUsername={!hasValidationError}
isValidPassword={!hasValidationError}
onChangeUsername={this.handleChangeUsername}
onChangePassword={this.handleChangePassword}
onLoginButtonClick={this.handleLoginButtonClick}
/>
</LoginPage>
);
}
}
export { AWXLogin as _AWXLogin };
export default withI18n()(withRouter(AWXLogin));