register.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. import React from 'react';
  2. import Button from 'misago/components/button'; // jshint ignore:line
  3. import Form from 'misago/components/form';
  4. import FormGroup from 'misago/components/form-group'; // jshint ignore:line
  5. import PasswordStrength from 'misago/components/password-strength'; // jshint ignore:line
  6. import misago from 'misago';
  7. import ajax from 'misago/services/ajax';
  8. import auth from 'misago/services/auth'; // jshint ignore:line
  9. import captcha from 'misago/services/captcha';
  10. import modal from 'misago/services/modal';
  11. import snackbar from 'misago/services/snackbar';
  12. import showBannedPage from 'misago/utils/banned-page';
  13. import * as validators from 'misago/utils/validators';
  14. export class RegisterForm extends Form {
  15. constructor(props) {
  16. super(props);
  17. this.state = {
  18. isLoading: false,
  19. username: '',
  20. email: '',
  21. password: '',
  22. captcha: '',
  23. validators: {
  24. username: [
  25. validators.usernameContent(),
  26. validators.usernameMinLength(misago.get('SETTINGS')),
  27. validators.usernameMaxLength(misago.get('SETTINGS'))
  28. ],
  29. email: [
  30. validators.email()
  31. ],
  32. password: [
  33. validators.passwordMinLength(misago.get('SETTINGS'))
  34. ],
  35. captcha: captcha.validator()
  36. },
  37. errors: {}
  38. };
  39. }
  40. clean() {
  41. if (this.isValid()) {
  42. return true;
  43. } else {
  44. snackbar.error(gettext("Form contains errors."));
  45. this.setState({
  46. errors: this.validate()
  47. });
  48. return false;
  49. }
  50. }
  51. send() {
  52. return ajax.post(misago.get('USERS_API'), {
  53. username: this.state.username,
  54. email: this.state.email,
  55. password: this.state.password,
  56. captcha: this.state.captcha
  57. });
  58. }
  59. handleSuccess(apiResponse) {
  60. this.props.callback(apiResponse);
  61. }
  62. handleError(rejection) {
  63. if (rejection.status === 400) {
  64. this.setState({
  65. 'errors': Object.assign({}, this.state.errors, rejection)
  66. });
  67. if (rejection.__all__ && rejection.__all__.length > 0) {
  68. snackbar.error(rejection.__all__[0]);
  69. } else {
  70. snackbar.error(gettext("Form contains errors."));
  71. }
  72. } else if (rejection.status === 403 && rejection.ban) {
  73. showBannedPage(rejection.ban);
  74. modal.hide();
  75. } else {
  76. snackbar.apiError(rejection);
  77. }
  78. }
  79. getLegalFootNote() {
  80. if (misago.get('TERMS_OF_SERVICE_URL')) {
  81. /* jshint ignore:start */
  82. return <a href={misago.get('TERMS_OF_SERVICE_URL')}
  83. target="_blank">
  84. {gettext("By registering you agree to site's terms and conditions.")}
  85. </a>;
  86. /* jshint ignore:end */
  87. } else {
  88. return null;
  89. }
  90. }
  91. render() {
  92. /* jshint ignore:start */
  93. return <div className="modal-dialog modal-register" role="document">
  94. <div className="modal-content">
  95. <div className="modal-header">
  96. <button type="button" className="close" data-dismiss="modal"
  97. aria-label={gettext("Close")}>
  98. <span aria-hidden="true">&times;</span>
  99. </button>
  100. <h4 className="modal-title">{gettext("Register")}</h4>
  101. </div>
  102. <form onSubmit={this.handleSubmit} className="form-horizontal">
  103. <input type="type" style={{display: 'none'}} />
  104. <input type="password" style={{display: 'none'}} />
  105. <div className="modal-body">
  106. <FormGroup label={gettext("Username")} for="id_username"
  107. labelClass="col-sm-4" controlClass="col-sm-8"
  108. validation={this.state.errors.username}>
  109. <input type="text" id="id_username" className="form-control"
  110. aria-describedby="id_username_status"
  111. disabled={this.state.isLoading}
  112. onChange={this.bindInput('username')}
  113. value={this.state.username} />
  114. </FormGroup>
  115. <FormGroup label={gettext("E-mail")} for="id_email"
  116. labelClass="col-sm-4" controlClass="col-sm-8"
  117. validation={this.state.errors.email}>
  118. <input type="text" id="id_email" className="form-control"
  119. aria-describedby="id_email_status"
  120. disabled={this.state.isLoading}
  121. onChange={this.bindInput('email')}
  122. value={this.state.email} />
  123. </FormGroup>
  124. <FormGroup label={gettext("Password")} for="id_password"
  125. labelClass="col-sm-4" controlClass="col-sm-8"
  126. validation={this.state.errors.password}
  127. extra={<PasswordStrength password={this.state.password}
  128. inputs={[
  129. this.state.username,
  130. this.state.email
  131. ]} />} >
  132. <input type="password" id="id_password" className="form-control"
  133. aria-describedby="id_password_status"
  134. disabled={this.state.isLoading}
  135. onChange={this.bindInput('password')}
  136. value={this.state.password} />
  137. </FormGroup>
  138. {captcha.component({
  139. form: this,
  140. labelClass: "col-sm-4",
  141. controlClass: "col-sm-8"
  142. })}
  143. </div>
  144. <div className="modal-footer">
  145. {this.getLegalFootNote()}
  146. <Button className="btn-primary" loading={this.state.isLoading}>
  147. {gettext("Register account")}
  148. </Button>
  149. </div>
  150. </form>
  151. </div>
  152. </div>;
  153. /* jshint ignore:end */
  154. }
  155. }
  156. export class RegisterComplete extends React.Component {
  157. getLead() {
  158. if (this.props.activation === 'user') {
  159. return gettext("%(username)s, your account has been created but you need to activate it before you will be able to sign in.");
  160. } else if (this.props.activation === 'admin') {
  161. return gettext("%(username)s, your account has been created but board administrator will have to activate it before you will be able to sign in.");
  162. }
  163. }
  164. getSubscript() {
  165. if (this.props.activation === 'user') {
  166. return gettext("We have sent an e-mail to %(email)s with link that you have to click to activate your account.");
  167. } else if (this.props.activation === 'admin') {
  168. return gettext("We will send an e-mail to %(email)s when this takes place.");
  169. }
  170. }
  171. render() {
  172. /* jshint ignore:start */
  173. return <div className="modal-dialog modal-message modal-register"
  174. role="document">
  175. <div className="modal-content">
  176. <div className="modal-header">
  177. <button type="button" className="close" data-dismiss="modal"
  178. aria-label={gettext("Close")}>
  179. <span aria-hidden="true">&times;</span>
  180. </button>
  181. <h4 className="modal-title">{gettext("Registration complete")}</h4>
  182. </div>
  183. <div className="modal-body">
  184. <div className="message-icon">
  185. <span className="material-icon">
  186. info_outline
  187. </span>
  188. </div>
  189. <div className="message-body">
  190. <p className="lead">
  191. {interpolate(
  192. this.getLead(),
  193. {'username': this.props.username}, true)}
  194. </p>
  195. <p>
  196. {interpolate(
  197. this.getSubscript(),
  198. {'email': this.props.email}, true)}
  199. </p>
  200. </div>
  201. </div>
  202. </div>
  203. </div>;
  204. /* jshint ignore:end */
  205. }
  206. }
  207. export default class extends React.Component {
  208. constructor(props) {
  209. super(props);
  210. this.state = {
  211. complete: false
  212. };
  213. }
  214. /* jshint ignore:start */
  215. completeRegistration = (apiResponse) => {
  216. if (apiResponse.activation === 'active') {
  217. modal.hide();
  218. auth.signIn(apiResponse);
  219. } else {
  220. this.setState({
  221. complete: apiResponse
  222. });
  223. }
  224. };
  225. /* jshint ignore:end */
  226. render() {
  227. /* jshint ignore:start */
  228. if (this.state.complete) {
  229. return <RegisterComplete activation={this.state.complete.activation}
  230. username={this.state.complete.username}
  231. email={this.state.complete.email} />;
  232. } else {
  233. return <RegisterForm callback={this.completeRegistration}/>;
  234. }
  235. /* jshint ignore:end */
  236. }
  237. }