Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

js: users module refactoring #1233

Merged
merged 1 commit into from
Mar 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
{
"env": {
"jquery": true,
"browser": true,
"browser": true
},
"extends": "airbnb-base",
"globals": {
"Bloodhound": false,
"layout_resizer": false,
"set_typeahead": false,
"open_close_icon": false
},
"plugins": [
"import"
Expand Down
6 changes: 4 additions & 2 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ require('vendor/bootstrap-typeahead');
// Require tree.
// NOTE: This should be moved into proper modules.
require('./alert');
require('./auth/cover');
require('./auth/registrations');
require('./bootstrap');
require('./dashboard');
require('./includes/open_close_icon');
Expand All @@ -27,3 +25,7 @@ require('./namespaces');
require('./open_search');
require('./repositories');
require('./teams');

// new modules structure
require('./modules/users');

8 changes: 0 additions & 8 deletions app/assets/javascripts/auth/cover.js

This file was deleted.

55 changes: 0 additions & 55 deletions app/assets/javascripts/auth/registrations.js

This file was deleted.

39 changes: 39 additions & 0 deletions app/assets/javascripts/base/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* eslint-disable class-methods-use-this */

// BaseComponent class to avoid boilerplate code
// into component classes and add some convention.
//
// The subclasses are not obligated to implement all
// of these methods but if they need to perform an action
// that fits one of the descriptions below, it's highly
// recommended to use the proper method.
class BaseComponent {
// Calls in order 'elements()', 'events()', 'beforeMount()',
// 'mount()' and 'mounted()'.
constructor(el) {
this.$el = el;

this.elements();
this.events();
this.beforeMount();
this.mount();
this.mounted();
}

// Caches HTML elements for further use.
elements() { }

// Attaches listeners to events triggered by HTML elements.
events() { }

// Before mount hook.
beforeMount() { }

// Renders the component.
mount() { }

// After mount hook.
mounted() { }
}

export default BaseComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import BaseComponent from '~/base/component';

const TOGGLE_LINK = '#add_application_token_btn';
const TOGGLE_LINK_ICON = `${TOGGLE_LINK} i`;
const APP_TOKEN_FORM = '#add_application_token_form';
const APP_TOKEN_FIELD = '#application_token_application';

// ApplicationTokenPanel component that handles application
// token interactions.
class ApplicationTokenPanel extends BaseComponent {
elements() {
this.$toggle = this.$el.find(TOGGLE_LINK);
this.$toggleIcon = this.$el.find(TOGGLE_LINK_ICON);
this.$form = this.$el.find(APP_TOKEN_FORM);
this.$token = this.$el.find(APP_TOKEN_FIELD);
}

events() {
this.$el.on('click', TOGGLE_LINK, e => this.onClick(e));
}

onClick() {
this.$form.toggle(400, 'swing', () => {
const visible = this.$form.is(':visible');

if (visible) {
this.clearFields();
}

this.$toggleIcon.toggleClass('fa-minus-circle', visible);
this.$toggleIcon.toggleClass('fa-plus-circle', !visible);

layout_resizer();
});
}

clearFields() {
this.$token.val('');
this.$token.focus();
}
}

export default ApplicationTokenPanel;
42 changes: 42 additions & 0 deletions app/assets/javascripts/modules/users/components/password-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import BaseComponent from '~/base/component';

const CURRENT_PASSWORD_FIELD = '#user_current_password';
const NEW_PASSWORD_FIELD = '#user_password';
const NEW_CONFIRMATION_PASSWORD_FIELD = '#user_password_confirmation';
const SUBMIT_BUTTON = 'input[type=submit]';

// UsersPasswordForm component that handles user password form
// interactions.
class UsersPasswordForm extends BaseComponent {
elements() {
this.$currentPassword = this.$el.find(CURRENT_PASSWORD_FIELD);
this.$newPassword = this.$el.find(NEW_PASSWORD_FIELD);
this.$newPasswordConfirmation = this.$el.find(NEW_CONFIRMATION_PASSWORD_FIELD);
this.$submit = this.$el.find(SUBMIT_BUTTON);
}

events() {
this.$el.on('keyup', CURRENT_PASSWORD_FIELD, e => this.onKeyup(e));
this.$el.on('keyup', NEW_PASSWORD_FIELD, e => this.onKeyup(e));
this.$el.on('keyup', NEW_CONFIRMATION_PASSWORD_FIELD, e => this.onKeyup(e));
}

onKeyup() {
const currentPassword = this.$currentPassword.val();
const newPassword = this.$newPassword.val();
const newPasswordConfirmation = this.$newPasswordConfirmation.val();

const currentPasswordInvalid = !currentPassword;
const newPasswordInvalid = !newPassword;
const newPasswordConfirmationInvalid = !newPasswordConfirmation ||
newPassword !== newPasswordConfirmation;

if (currentPasswordInvalid || newPasswordInvalid || newPasswordConfirmationInvalid) {
this.$submit.attr('disabled', 'disabled');
} else {
this.$submit.removeAttr('disabled');
}
}
}

export default UsersPasswordForm;
42 changes: 42 additions & 0 deletions app/assets/javascripts/modules/users/components/profile-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import BaseComponent from '~/base/component';

const EMAIL_FIELD = '#user_email';
const DISPLAY_NAME_FIELD = '#user_display_name';
const SUBMIT_BUTTON = 'input[type=submit]';

// UsersProfileForm component handles user profile form
// interactions.
class UsersProfileForm extends BaseComponent {
elements() {
this.$email = this.$el.find(EMAIL_FIELD);
this.$displayName = this.$el.find(DISPLAY_NAME_FIELD);
this.$submit = this.$el.find(SUBMIT_BUTTON);
}

events() {
this.$el.on('keyup', EMAIL_FIELD, e => this.onKeyup(e));
this.$el.on('keyup', DISPLAY_NAME_FIELD, e => this.onKeyup(e));
}

onKeyup() {
const email = this.$email.val();
const displayName = this.$displayName.val();

const emailInvalid = !email || email === this.originalEmail;
const displayNameInvalid = this.$displayName[0] &&
(!displayName || displayName === this.originalDisplayName);

if (emailInvalid || displayNameInvalid) {
this.$submit.attr('disabled', 'disabled');
} else {
this.$submit.removeAttr('disabled');
}
}

mounted() {
this.originalEmail = this.$email.val();
this.originalDisplayName = this.$displayName.val();
}
}

export default UsersProfileForm;
27 changes: 27 additions & 0 deletions app/assets/javascripts/modules/users/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import UsersEditPage from './pages/edit';
import UsersSignUpPage from './pages/sign-up';
import UsersSignInPage from './pages/sign-in';

const USERS_EDIT_ROUTE = 'auth/registrations/edit';
const USERS_SIGN_IN_ROUTE = 'auth/sessions/new';
const USERS_SIGN_UP_ROUTE = 'auth/registrations/new';

$(() => {
const $body = $('body');
const route = $body.data('route');

if (route === USERS_EDIT_ROUTE) {
// eslint-disable-next-line
new UsersEditPage($body);
}

if (route === USERS_SIGN_UP_ROUTE) {
// eslint-disable-next-line
new UsersSignUpPage($body);
}

if (route === USERS_SIGN_IN_ROUTE) {
// eslint-disable-next-line
new UsersSignInPage($body);
}
});
27 changes: 27 additions & 0 deletions app/assets/javascripts/modules/users/pages/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import BaseComponent from '~/base/component';

import ProfileForm from '../components/profile-form';
import PasswordForm from '../components/password-form';
import ApplicationTokenPanel from '../components/application-token-panel';

const PROFILE_FORM = 'form.profile';
const PASSWORD_FORM = 'form.password';
const APP_TOKEN_PANEL = '.app-token-wrapper';

// UsersEditPage component responsible to instantiate
// the user's edit page components and handle interactions.
class UsersEditPage extends BaseComponent {
elements() {
this.$profileForm = this.$el.find(PROFILE_FORM);
this.$passwordForm = this.$el.find(PASSWORD_FORM);
this.$appTokenPanel = this.$el.find(APP_TOKEN_PANEL);
}

mount() {
this.profileForm = new ProfileForm(this.$profileForm);
this.passwordForm = new PasswordForm(this.$passwordForm);
this.appTokenPanel = new ApplicationTokenPanel(this.$appTokenPanel);
}
}

export default UsersEditPage;
13 changes: 13 additions & 0 deletions app/assets/javascripts/modules/users/pages/sign-in.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import BaseComponent from '~/base/component';

import { fadeIn } from '~/utils/effects';

// UsersSignInPage component responsible to instantiate
// the user's sign in page components and handle interactions.
class UsersSignInPage extends BaseComponent {
mount() {
fadeIn(this.$el);
}
}

export default UsersSignInPage;
13 changes: 13 additions & 0 deletions app/assets/javascripts/modules/users/pages/sign-up.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import BaseComponent from '~/base/component';

import { fadeIn } from '~/utils/effects';

// UsersSignUpPage component responsible to instantiate
// the user's sign up page components and handle interactions.
class UsersSignUpPage extends BaseComponent {
mount() {
fadeIn(this.$el);
}
}

export default UsersSignUpPage;
5 changes: 0 additions & 5 deletions app/assets/javascripts/namespaces.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
/* global layout_resizer, set_typeahead, open_close_icon */

//= require includes/set_typehead
//= require includes/open_close_icon

jQuery(function ($) {
$('#edit_namespace').on('click', function (_event) {
set_typeahead('/teams/typeahead/%QUERY');
Expand Down
2 changes: 0 additions & 2 deletions app/assets/javascripts/repositories.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/* global layout_resizer */

jQuery(function ($) {
// Shows and hides the comment form
$('#write_comment_repository_btn').unbind('click').on('click', function (_e) {
Expand Down
4 changes: 0 additions & 4 deletions app/assets/javascripts/teams.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
/* global layout_resizer, set_typeahead, open_close_icon */

//= require namespaces

jQuery(function ($) {
$('#add_team_user_btn').on('click', function (_event) {
var team_id;
Expand Down
12 changes: 12 additions & 0 deletions app/assets/javascripts/utils/effects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// after jquery was upgraded this effect was conflicting
// with lifeitup functions (probably layout_resizer)
// so setTimeout was the workaround I found to solve the error
export const fadeIn = function ($el) {
setTimeout(() => {
$el.hide().fadeIn(1000);
}, 0);
};

export default {
fadeIn,
};
Loading