A React interface for Ampache player.

Login.jsx 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import React, { Component, PropTypes } from "react";
  2. import { defineMessages, injectIntl, intlShape, FormattedMessage } from "react-intl";
  3. import { messagesMap } from "../utils";
  4. import messages from "../locales/messagesDescriptors/Login";
  5. const loginMessages = defineMessages(messagesMap(messages));
  6. class LoginFormIntl extends Component {
  7. constructor (props) {
  8. super(props);
  9. this.handleSubmit = this.handleSubmit.bind(this);
  10. }
  11. setError (formGroup, error) {
  12. if (error) {
  13. formGroup.classList.add("has-error");
  14. formGroup.classList.remove("has-success");
  15. return true;
  16. }
  17. formGroup.classList.remove("has-error");
  18. formGroup.classList.add("has-success");
  19. return false;
  20. }
  21. handleSubmit (e) {
  22. e.preventDefault();
  23. if (this.props.isAuthenticating) {
  24. // Don't handle submit if already logging in
  25. return;
  26. }
  27. const username = this.refs.username.value.trim();
  28. const password = this.refs.password.value.trim();
  29. const endpoint = this.refs.endpoint.value.trim();
  30. const rememberMe = this.refs.rememberMe.checked;
  31. var hasError = this.setError(this.refs.usernameFormGroup, !username);
  32. hasError |= this.setError(this.refs.passwordFormGroup, !password);
  33. hasError |= this.setError(this.refs.endpointFormGroup, !endpoint);
  34. if (!hasError) {
  35. this.props.onSubmit(username, password, endpoint, rememberMe);
  36. }
  37. }
  38. componentDidUpdate () {
  39. if (this.props.error) {
  40. $(this.refs.loginForm).shake(3, 10, 300);
  41. this.setError(this.refs.usernameFormGroup, this.props.error);
  42. this.setError(this.refs.passwordFormGroup, this.props.error);
  43. this.setError(this.refs.endpointFormGroup, this.props.error);
  44. }
  45. }
  46. render () {
  47. const {formatMessage} = this.props.intl;
  48. return (
  49. <div>
  50. { /* TODO: info/error translation */ }
  51. {
  52. this.props.error ?
  53. <div className="row">
  54. <div className="alert alert-danger">
  55. <p id="loginFormError">
  56. <span className="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> { this.props.error }
  57. </p>
  58. </div>
  59. </div>
  60. : null
  61. }
  62. {
  63. this.props.info ?
  64. <div className="row">
  65. <div className="alert alert-info" id="loginFormInfo">
  66. <p>{ this.props.info }</p>
  67. </div>
  68. </div>
  69. : null
  70. }
  71. <div className="row">
  72. <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">
  73. <div className="row">
  74. <div className="form-group" ref="usernameFormGroup">
  75. <div className="col-xs-12">
  76. <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} />
  77. </div>
  78. </div>
  79. <div className="form-group" ref="passwordFormGroup">
  80. <div className="col-xs-12">
  81. <input type="password" className="form-control" ref="password" aria-label={formatMessage(loginMessages["app.login.password"])} placeholder={formatMessage(loginMessages["app.login.password"])} />
  82. </div>
  83. </div>
  84. <div className="form-group" ref="endpointFormGroup">
  85. <div className="col-xs-12">
  86. <input type="text" className="form-control" ref="endpoint" aria-label={formatMessage(loginMessages["app.login.endpointInputAriaLabel"])} placeholder="http://ampache.example.com" defaultValue={this.props.endpoint} />
  87. </div>
  88. </div>
  89. <div className="form-group">
  90. <div className="col-xs-12">
  91. <div className="row">
  92. <div className="col-sm-6 col-xs-12 checkbox">
  93. <label id="rememberMeLabel">
  94. <input type="checkbox" ref="rememberMe" defaultChecked={this.props.rememberMe} aria-labelledby="rememberMeLabel" />
  95. <FormattedMessage {...loginMessages["app.login.rememberMe"]} />
  96. </label>
  97. </div>
  98. <div className="col-sm-6 col-sm-12 submit text-right">
  99. <input type="submit" className="btn btn-default" aria-label={formatMessage(loginMessages["app.login.signIn"])} defaultValue={formatMessage(loginMessages["app.login.signIn"])} disabled={this.props.isAuthenticating} />
  100. </div>
  101. </div>
  102. </div>
  103. </div>
  104. </div>
  105. </form>
  106. </div>
  107. </div>
  108. );
  109. }
  110. }
  111. LoginFormIntl.propTypes = {
  112. username: PropTypes.string,
  113. endpoint: PropTypes.string,
  114. rememberMe: PropTypes.bool,
  115. onSubmit: PropTypes.func.isRequired,
  116. isAuthenticating: PropTypes.bool,
  117. error: PropTypes.string,
  118. info: PropTypes.string,
  119. intl: intlShape.isRequired,
  120. };
  121. export let LoginForm = injectIntl(LoginFormIntl);
  122. export default class Login extends Component {
  123. render () {
  124. const greeting = (
  125. <p>
  126. <FormattedMessage {...loginMessages["app.login.greeting"]} />
  127. </p>
  128. );
  129. return (
  130. <div className="login text-center container-fluid">
  131. <h1><img src="./app/assets/img/ampache-blue.png" alt="A"/>mpache</h1>
  132. <hr/>
  133. {(!this.props.error && !this.props.info) ? greeting : null}
  134. <div className="col-sm-9 col-sm-offset-2 col-md-6 col-md-offset-3">
  135. <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} />
  136. </div>
  137. </div>
  138. );
  139. }
  140. }
  141. Login.propTypes = {
  142. username: PropTypes.string,
  143. endpoint: PropTypes.string,
  144. rememberMe: PropTypes.bool,
  145. onSubmit: PropTypes.func.isRequired,
  146. isAuthenticating: PropTypes.bool,
  147. error: PropTypes.string,
  148. info: PropTypes.string
  149. };