summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/pages/sessions/new/username_validator.js
blob: 1848aa70cf0d80c0e416118a1dd74ab6fdd52232 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import { debounce } from 'lodash';

import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import InputValidator from '~/validators/input_validator';

const debounceTimeoutDuration = 1000;
const rootUrl = gon.relative_url_root;
const invalidInputClass = 'gl-field-error-outline';
const successInputClass = 'gl-field-success-outline';
const successMessageSelector = '.validation-success';
const pendingMessageSelector = '.validation-pending';
const unavailableMessageSelector = '.validation-error';

export default class UsernameValidator extends InputValidator {
  constructor(opts = {}) {
    super();

    const container = opts.container || '';
    const validateLengthElements = document.querySelectorAll(`${container} .js-validate-username`);

    this.debounceValidateInput = debounce((inputDomElement) => {
      UsernameValidator.validateUsernameInput(inputDomElement);
    }, debounceTimeoutDuration);

    validateLengthElements.forEach((element) =>
      element.addEventListener('input', this.eventHandler.bind(this)),
    );
  }

  eventHandler(event) {
    const inputDomElement = event.target;

    UsernameValidator.resetInputState(inputDomElement);
    this.debounceValidateInput(inputDomElement);
  }

  static validateUsernameInput(inputDomElement) {
    const username = inputDomElement.value;

    if (inputDomElement.checkValidity() && username.length > 1) {
      UsernameValidator.setMessageVisibility(inputDomElement, pendingMessageSelector);
      UsernameValidator.fetchUsernameAvailability(username)
        .then((usernameTaken) => {
          UsernameValidator.setInputState(inputDomElement, !usernameTaken);
          UsernameValidator.setMessageVisibility(inputDomElement, pendingMessageSelector, false);
          UsernameValidator.setMessageVisibility(
            inputDomElement,
            usernameTaken ? unavailableMessageSelector : successMessageSelector,
          );
        })
        .catch(() =>
          createAlert({
            message: __('An error occurred while validating username'),
          }),
        );
    }
  }

  static fetchUsernameAvailability(username) {
    return axios.get(`${rootUrl}/users/${username}/exists`).then(({ data }) => data.exists);
  }

  static setMessageVisibility(inputDomElement, messageSelector, isVisible = true) {
    const messageElement = inputDomElement.parentElement.querySelector(messageSelector);
    messageElement.classList.toggle('hide', !isVisible);
  }

  static setInputState(inputDomElement, success = true) {
    inputDomElement.classList.toggle(successInputClass, success);
    inputDomElement.classList.toggle(invalidInputClass, !success);
  }

  static resetInputState(inputDomElement) {
    UsernameValidator.setMessageVisibility(inputDomElement, successMessageSelector, false);
    UsernameValidator.setMessageVisibility(inputDomElement, unavailableMessageSelector, false);

    if (inputDomElement.checkValidity()) {
      inputDomElement.classList.remove(successInputClass, invalidInputClass);
    }
  }
}