From 3ac1989c735c1c4c7a0ae9df9b903caaa18b6db3 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Wed, 8 Jun 2016 08:52:10 +0100 Subject: Added /u/:username/exists endpoint and added input debouncing for request added error message Renamed file changed error delivery Review fixes --- app/assets/javascripts/dispatcher.js | 2 + app/assets/javascripts/username_validator.es6 | 51 +++++++++++++++++++++++ app/assets/stylesheets/pages/login.scss | 15 +++++++ app/controllers/users_controller.rb | 4 ++ app/views/devise/shared/_signup_box.html.haml | 59 ++++++++++++++------------- config/routes.rb | 1 + 6 files changed, 103 insertions(+), 29 deletions(-) create mode 100644 app/assets/javascripts/username_validator.es6 diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index ba64d2bcf0b..bf9c865f6eb 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -22,6 +22,8 @@ switch (page) { case 'projects:boards:show': shortcut_handler = new ShortcutsNavigation(); + case 'signup': + new UsernameValidator(); break; case 'projects:issues:index': Issuable.init(); diff --git a/app/assets/javascripts/username_validator.es6 b/app/assets/javascripts/username_validator.es6 new file mode 100644 index 00000000000..67dacb655cc --- /dev/null +++ b/app/assets/javascripts/username_validator.es6 @@ -0,0 +1,51 @@ +((global) => { + class UsernameValidator { + constructor() { + this.debounceTimeoutDuration = 1000; + this.errorIconClasses = 'fa fa-exclamation-circle error'; + this.usernameInUseMessage = 'Username "$1" is in use!'; + this.loadingIconClasses = 'fa fa-spinner fa-spin'; + this.successIconClasses = 'fa fa-check-circle success'; + this.tooltipPlacement = 'left'; + + this.inputElement = $('#new_user_username'); + let inputContainer = this.inputElement.parent(); + inputContainer.append(''); + this.iconElement = $('i', inputContainer); + + let debounceTimeout = _.debounce(this.validateUsername, debounceTimeoutDuration); + this.inputElement.keyup(() => this.debounceRequest(debounceTimeout)); + } + + debounceRequest(debounceTimeout) { + this.iconElement.removeClass().tooltip('destroy'); + let username = this.inputElement.val(); + if (username === '') return; + this.iconElement.addClass(loadingIconClasses); + debounceTimeout(username); + } + + validateUsername(username) { + $.ajax({ + type: 'GET', + url: `/u/${username}/exists`, + dataType: 'json', + success: () => { + this.iconElement + .removeClass().addClass(errorIconClasses) + .tooltip({ + title: usernameInUseMessage.replace(/\$1/g, username), + placement: tooltipPlacement + }); + }, + error: () => { + this.iconElement + .removeClass().addClass(successIconClasses) + .tooltip('destroy') + } + }); + } + } + + global.UsernameValidator = UsernameValidator; +})(window); diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss index 403171d4532..042b17b865a 100644 --- a/app/assets/stylesheets/pages/login.scss +++ b/app/assets/stylesheets/pages/login.scss @@ -64,6 +64,21 @@ .nav .active a { background: transparent; } + + .login-body .new_new_user .username { + position: relative; + i { + position: absolute; + right: 8px; + top: 12px; + &.success { + color: $green-normal; + } + &.error { + color: $red-normal; + } + } + } } .form-control { diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index a99632454d9..cfee71e9785 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -85,6 +85,10 @@ class UsersController < ApplicationController render 'calendar_activities', layout: false end + def exists + render json: user.id + end + private def authorize_read_user! diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml index 905a8dbcd84..5ec914763fe 100644 --- a/app/views/devise/shared/_signup_box.html.haml +++ b/app/views/devise/shared/_signup_box.html.haml @@ -1,30 +1,31 @@ -.login-box - - if signin_enabled? - .login-heading - %h3 New user? Create an account - - else - .login-heading - %h3 Create an account - .login-body - = form_for(resource, as: "new_#{resource_name}", url: registration_path(resource_name)) do |f| - .devise-errors - = devise_error_messages! - %div - = f.text_field :name, class: "form-control top", placeholder: "Name", required: true - %div - = f.text_field :username, class: "form-control middle", placeholder: "Username", required: true - %div - = f.email_field :email, class: "form-control middle", placeholder: "Email", required: true - .form-group.append-bottom-20#password-strength - = f.password_field :password, class: "form-control bottom", placeholder: "Password - minimum length #{@minimum_password_length} characters", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters" - %div - - if current_application_settings.recaptcha_enabled - = recaptcha_tags - %div - = f.submit "Sign up", class: "btn-create btn" +%body{ data: { page: 'signup' } } + .login-box + - if signin_enabled? + .login-heading + %h3 New user? Create an account + - else + .login-heading + %h3 Create an account + .login-body + = form_for(resource, as: "new_#{resource_name}", url: registration_path(resource_name)) do |f| + .devise-errors + = devise_error_messages! + %div + = f.text_field :name, class: "form-control top", placeholder: "Name", required: true + %div.username + = f.text_field :username, class: "form-control middle", placeholder: "Username", required: true + %div + = f.email_field :email, class: "form-control middle", placeholder: "Email", required: true + .form-group.append-bottom-20#password-strength + = f.password_field :password, class: "form-control bottom", placeholder: "Password - minimum length #{@minimum_password_length} characters", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters" + %div + - if current_application_settings.recaptcha_enabled + = recaptcha_tags + %div + = f.submit "Sign up", class: "btn-create btn" -.clearfix.prepend-top-20 - %p - %span.light Didn't receive a confirmation email? - = succeed '.' do - = link_to "Request a new one", new_confirmation_path(resource_name) + .clearfix.prepend-top-20 + %p + %span.light Didn't receive a confirmation email? + = succeed '.' do + = link_to "Request a new one", new_confirmation_path(resource_name) diff --git a/config/routes.rb b/config/routes.rb index e93b640fbc0..fde03dd07c3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -395,6 +395,7 @@ Rails.application.routes.draw do get :projects get :contributed, as: :contributed_projects get :snippets + get :exists get '/', action: :show end -- cgit v1.2.1