2016-07-07 23:23:18 +02:00
|
|
|
import React, { Component, PropTypes } from "react";
|
2016-07-29 23:57:21 +02:00
|
|
|
import CSSModules from "react-css-modules";
|
2016-07-28 23:14:52 +02:00
|
|
|
import { defineMessages, injectIntl, intlShape, FormattedMessage } from "react-intl";
|
2016-07-07 23:23:18 +02:00
|
|
|
|
2016-08-01 00:26:52 +02:00
|
|
|
import { i18nRecord } from "../models/i18n";
|
2016-07-28 23:14:52 +02:00
|
|
|
import { messagesMap } from "../utils";
|
2016-08-01 00:26:52 +02:00
|
|
|
import APIMessages from "../locales/messagesDescriptors/api";
|
2016-07-28 23:14:52 +02:00
|
|
|
import messages from "../locales/messagesDescriptors/Login";
|
|
|
|
|
2016-07-29 23:57:21 +02:00
|
|
|
import css from "../styles/Login.scss";
|
|
|
|
|
2016-08-01 00:26:52 +02:00
|
|
|
const loginMessages = defineMessages(messagesMap(Array.concat([], APIMessages, messages)));
|
2016-07-28 23:14:52 +02:00
|
|
|
|
2016-07-29 23:57:21 +02:00
|
|
|
class LoginFormCSSIntl extends Component {
|
2016-07-07 23:23:18 +02:00
|
|
|
constructor (props) {
|
2016-07-25 23:22:44 +02:00
|
|
|
super(props);
|
2016-07-07 23:23:18 +02:00
|
|
|
|
2016-07-25 23:22:44 +02:00
|
|
|
this.handleSubmit = this.handleSubmit.bind(this);
|
2016-07-07 23:23:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
setError (formGroup, error) {
|
|
|
|
if (error) {
|
|
|
|
formGroup.classList.add("has-error");
|
|
|
|
formGroup.classList.remove("has-success");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
formGroup.classList.remove("has-error");
|
|
|
|
formGroup.classList.add("has-success");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
handleSubmit (e) {
|
|
|
|
e.preventDefault();
|
2016-07-28 23:57:29 +02:00
|
|
|
if (this.props.isAuthenticating) {
|
|
|
|
// Don't handle submit if already logging in
|
|
|
|
return;
|
|
|
|
}
|
2016-07-07 23:23:18 +02:00
|
|
|
const username = this.refs.username.value.trim();
|
|
|
|
const password = this.refs.password.value.trim();
|
|
|
|
const endpoint = this.refs.endpoint.value.trim();
|
|
|
|
const rememberMe = this.refs.rememberMe.checked;
|
|
|
|
|
|
|
|
var hasError = this.setError(this.refs.usernameFormGroup, !username);
|
|
|
|
hasError |= this.setError(this.refs.passwordFormGroup, !password);
|
|
|
|
hasError |= this.setError(this.refs.endpointFormGroup, !endpoint);
|
|
|
|
|
|
|
|
if (!hasError) {
|
2016-07-25 23:22:44 +02:00
|
|
|
this.props.onSubmit(username, password, endpoint, rememberMe);
|
2016-07-07 23:23:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-25 23:22:44 +02:00
|
|
|
componentDidUpdate () {
|
2016-07-07 23:23:18 +02:00
|
|
|
if (this.props.error) {
|
|
|
|
$(this.refs.loginForm).shake(3, 10, 300);
|
|
|
|
this.setError(this.refs.usernameFormGroup, this.props.error);
|
|
|
|
this.setError(this.refs.passwordFormGroup, this.props.error);
|
|
|
|
this.setError(this.refs.endpointFormGroup, this.props.error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
2016-07-28 23:14:52 +02:00
|
|
|
const {formatMessage} = this.props.intl;
|
2016-08-01 00:26:52 +02:00
|
|
|
var infoMessage = this.props.info;
|
|
|
|
if (this.props.info && this.props.info instanceof i18nRecord) {
|
2016-07-31 01:05:08 +02:00
|
|
|
infoMessage = (
|
|
|
|
<FormattedMessage {...loginMessages[this.props.info.id]} values={ this.props.info.values} />
|
|
|
|
);
|
2016-08-01 00:26:52 +02:00
|
|
|
}
|
|
|
|
var errorMessage = this.props.error;
|
|
|
|
if (this.props.error && this.props.error instanceof i18nRecord) {
|
|
|
|
errorMessage = (
|
|
|
|
<FormattedMessage {...loginMessages[this.props.error.id]} values={ this.props.error.values} />
|
|
|
|
);
|
2016-07-31 01:05:08 +02:00
|
|
|
}
|
2016-07-07 23:23:18 +02:00
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
{
|
|
|
|
this.props.error ?
|
|
|
|
<div className="row">
|
2016-08-01 12:01:11 +02:00
|
|
|
<div className="alert alert-danger" id="loginFormError" role="alert">
|
2016-07-29 23:57:21 +02:00
|
|
|
<p>
|
2016-08-01 00:26:52 +02:00
|
|
|
<span className="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> { errorMessage }
|
2016-07-26 13:21:37 +02:00
|
|
|
</p>
|
2016-07-07 23:23:18 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
{
|
|
|
|
this.props.info ?
|
|
|
|
<div className="row">
|
2016-08-01 12:01:11 +02:00
|
|
|
<div className="alert alert-info" id="loginFormInfo" role="alert">
|
2016-07-31 01:05:08 +02:00
|
|
|
<p>{ infoMessage }</p>
|
2016-07-07 23:23:18 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
: null
|
|
|
|
}
|
|
|
|
<div className="row">
|
2016-07-26 13:21:37 +02:00
|
|
|
<form className="col-sm-9 col-sm-offset-1 col-md-6 col-md-offset-3 text-left form-horizontal login" onSubmit={this.handleSubmit} ref="loginForm" aria-describedby="loginFormInfo loginFormError">
|
2016-07-07 23:23:18 +02:00
|
|
|
<div className="row">
|
|
|
|
<div className="form-group" ref="usernameFormGroup">
|
|
|
|
<div className="col-xs-12">
|
2016-07-28 23:14:52 +02:00
|
|
|
<input type="text" className="form-control" ref="username" aria-label={formatMessage(loginMessages["app.login.username"])} placeholder={formatMessage(loginMessages["app.login.username"])} autoFocus defaultValue={this.props.username} />
|
2016-07-07 23:23:18 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className="form-group" ref="passwordFormGroup">
|
|
|
|
<div className="col-xs-12">
|
2016-07-28 23:14:52 +02:00
|
|
|
<input type="password" className="form-control" ref="password" aria-label={formatMessage(loginMessages["app.login.password"])} placeholder={formatMessage(loginMessages["app.login.password"])} />
|
2016-07-07 23:23:18 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className="form-group" ref="endpointFormGroup">
|
|
|
|
<div className="col-xs-12">
|
2016-07-28 23:14:52 +02:00
|
|
|
<input type="text" className="form-control" ref="endpoint" aria-label={formatMessage(loginMessages["app.login.endpointInputAriaLabel"])} placeholder="http://ampache.example.com" defaultValue={this.props.endpoint} />
|
2016-07-07 23:23:18 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className="form-group">
|
|
|
|
<div className="col-xs-12">
|
|
|
|
<div className="row">
|
|
|
|
<div className="col-sm-6 col-xs-12 checkbox">
|
2016-07-26 13:21:37 +02:00
|
|
|
<label id="rememberMeLabel">
|
2016-07-28 23:14:52 +02:00
|
|
|
<input type="checkbox" ref="rememberMe" defaultChecked={this.props.rememberMe} aria-labelledby="rememberMeLabel" />
|
|
|
|
<FormattedMessage {...loginMessages["app.login.rememberMe"]} />
|
2016-07-07 23:23:18 +02:00
|
|
|
</label>
|
|
|
|
</div>
|
2016-07-29 23:57:21 +02:00
|
|
|
<div className="col-sm-6 col-xs-12 text-right" styleName="submit">
|
2016-07-28 23:14:52 +02:00
|
|
|
<input type="submit" className="btn btn-default" aria-label={formatMessage(loginMessages["app.login.signIn"])} defaultValue={formatMessage(loginMessages["app.login.signIn"])} disabled={this.props.isAuthenticating} />
|
2016-07-07 23:23:18 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-29 23:57:21 +02:00
|
|
|
LoginFormCSSIntl.propTypes = {
|
2016-07-07 23:23:18 +02:00
|
|
|
username: PropTypes.string,
|
|
|
|
endpoint: PropTypes.string,
|
|
|
|
rememberMe: PropTypes.bool,
|
|
|
|
onSubmit: PropTypes.func.isRequired,
|
|
|
|
isAuthenticating: PropTypes.bool,
|
2016-08-01 00:26:52 +02:00
|
|
|
error: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(i18nRecord)]),
|
|
|
|
info: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(i18nRecord)]),
|
2016-07-28 23:14:52 +02:00
|
|
|
intl: intlShape.isRequired,
|
2016-07-07 23:23:18 +02:00
|
|
|
};
|
|
|
|
|
2016-07-29 23:57:21 +02:00
|
|
|
export let LoginForm = injectIntl(CSSModules(LoginFormCSSIntl, css));
|
2016-07-28 23:14:52 +02:00
|
|
|
|
2016-07-07 23:23:18 +02:00
|
|
|
|
2016-07-29 23:57:21 +02:00
|
|
|
class Login extends Component {
|
2016-07-07 23:23:18 +02:00
|
|
|
render () {
|
2016-07-28 23:14:52 +02:00
|
|
|
const greeting = (
|
|
|
|
<p>
|
|
|
|
<FormattedMessage {...loginMessages["app.login.greeting"]} />
|
|
|
|
</p>
|
|
|
|
);
|
2016-07-07 23:23:18 +02:00
|
|
|
return (
|
2016-07-29 23:57:21 +02:00
|
|
|
<div className="text-center container-fluid">
|
|
|
|
<h1><img styleName="titleImage" src="./app/assets/img/ampache-blue.png" alt="A"/>mpache</h1>
|
2016-07-07 23:23:18 +02:00
|
|
|
<hr/>
|
2016-07-28 23:14:52 +02:00
|
|
|
{(!this.props.error && !this.props.info) ? greeting : null}
|
2016-07-07 23:23:18 +02:00
|
|
|
<div className="col-sm-9 col-sm-offset-2 col-md-6 col-md-offset-3">
|
|
|
|
<LoginForm onSubmit={this.props.onSubmit} username={this.props.username} endpoint={this.props.endpoint} rememberMe={this.props.rememberMe} isAuthenticating={this.props.isAuthenticating} error={this.props.error} info={this.props.info} />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Login.propTypes = {
|
|
|
|
username: PropTypes.string,
|
|
|
|
endpoint: PropTypes.string,
|
|
|
|
rememberMe: PropTypes.bool,
|
|
|
|
onSubmit: PropTypes.func.isRequired,
|
|
|
|
isAuthenticating: PropTypes.bool,
|
2016-08-02 13:07:12 +02:00
|
|
|
info: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
|
|
|
error: PropTypes.oneOfType([PropTypes.string, PropTypes.object])
|
2016-07-07 23:23:18 +02:00
|
|
|
};
|
2016-07-29 23:57:21 +02:00
|
|
|
|
|
|
|
export default CSSModules(Login, css);
|