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

Commit

Permalink
js (users): module refactoring
Browse files Browse the repository at this point in the history
Signed-off-by: Vítor Avelino <[email protected]>
  • Loading branch information
vitoravelino committed Mar 14, 2017
1 parent 64d3677 commit 3b7488a
Show file tree
Hide file tree
Showing 21 changed files with 339 additions and 116 deletions.
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

0 comments on commit 3b7488a

Please sign in to comment.