Add first version of invite users modal

This commit is contained in:
Luka Murn 2016-11-03 11:27:17 +01:00
parent 12d1c31651
commit ccf8932611
7 changed files with 333 additions and 0 deletions

View file

@ -0,0 +1,164 @@
(function() {
'use strict';
function initializeModal(modal) {
var modalDialog = modal.find('.modal-dialog');
var type = modal.attr('data-type');
var stepForm = modal.find('[data-role=step-form]');
var stepResults = modal.find('[data-role=step-results]');
var inviteBtn = modal.find('[data-role=invite-btn]');
var inviteWithRoleDiv =
modal.find('[data-role=invite-with-role-div]');
var inviteWithRoleBtn =
modal.find('[data-role=invite-with-role-btn]');
var orgSelectorCheckbox =
modal.find('[data-role=org-selector-checkbox]');
var orgSelectorDropdown =
modal.find('[data-role=org-selector-dropdown]');
var orgSelectorDropdown2 = $();
var tagsInput = modal.find('[data-role=tagsinput]');
modal
.on('show.bs.modal', function() {
// This cannot be scoped outside this function
// because it is generated via JS
orgSelectorDropdown2 =
orgSelectorDropdown
.next('.btn-group.bootstrap-select.form-control')
.find('button.dropdown-toggle, li');
// Show/hide correct step
stepForm.show();
stepResults.hide();
// Show/hide buttons & other elements
switch (type) {
case 'invite_to_org_with_role':
case 'invite':
case 'invite_with_org_selector':
case 'invite_with_org_selector_and_role':
inviteBtn.show();
inviteWithRoleDiv.hide();
break;
case 'invite_to_org':
inviteBtn.hide();
inviteWithRoleDiv.show();
break;
default:
break;
}
// Checkbox toggle event
if (
type === 'invite_with_org_selector' ||
type === 'invite_with_org_selector_and_role'
) {
orgSelectorCheckbox.on('change', function() {
if ($(this).is(':checked')) {
orgSelectorDropdown.removeAttr('disabled');
orgSelectorDropdown2.removeClass('disabled');
if (type === 'invite_with_org_selector') {
inviteBtn.hide();
inviteWithRoleDiv.show();
}
} else {
orgSelectorDropdown.attr('disabled', 'disabled');
orgSelectorDropdown2.addClass('disabled');
if (type === 'invite_with_org_selector') {
inviteBtn.show();
inviteWithRoleDiv.hide();
}
}
});
}
// Toggle depending on input tags
tagsInput
.on('itemAdded', function(event) {
inviteBtn.removeAttr('disabled');
inviteWithRoleBtn.removeAttr('disabled');
})
.on('itemRemoved', function(event) {
if ($(this).val() === null) {
inviteBtn.attr('disabled', 'disabled');
inviteWithRoleBtn.attr('disabled', 'disabled');
}
});
// Click action
$('[data-action=invite]').on('click', function() {
animateSpinner(modalDialog);
var data = {
emails: tagsInput.val()
};
switch (type) {
case 'invite_to_org':
data.organizationId = modal.attr('data-organization-id');
data.role = $(this).attr('data-organization-role');
break;
case 'invite_to_org_with_role':
data.organizationId = modal.attr('data-organization-id');
data.role = modal.attr('data-organization-role');
break;
case 'invite':
break;
case 'invite_with_org_selector':
if (orgSelectorCheckbox.is(':checked')) {
data.organizationId = orgSelectorDropdown.val();
data.role = $(this).attr('data-organization-role');
}
break;
case 'invite_with_org_selector_and_role':
if (orgSelectorCheckbox.is(':checked')) {
data.organizationId = orgSelectorDropdown.val();
data.role = modal.attr('data-organization-role');
}
break;
default:
break;
}
$.ajax({
method: 'POST',
url: modal.attr('data-url'),
dataType: 'json',
data: data,
success: function(data) {
}
});
});
})
.on('shown.bs.modal', function() {
tagsInput.tagsinput('focus');
})
.on('hide.bs.modal', function() {
// 'Reset' modal state
tagsInput.tagsinput('removeAll');
orgSelectorCheckbox.prop('checked', false);
inviteBtn.attr('disabled', 'disabled');
inviteWithRoleBtn.attr('disabled', 'disabled');
orgSelectorDropdown2.addClass('disabled');
animateSpinner(modalDialog, false);
// Unbind event listeners
orgSelectorCheckbox.off('change');
tagsInput.off('itemAdded itemRemoved');
});
}
function initializeModalsToggle() {
$("[data-trigger='invite-users']").on('click', function() {
var id = $(this).attr('data-modal-id');
$('[data-role=invite-users-modal][data-id=' + id + ']')
.modal('show');
});
}
$(document).ready(function() {
$('[data-role=invite-users-modal]').each(function() {
initializeModal($(this));
});
initializeModalsToggle();
});
})();

View file

@ -1496,3 +1496,19 @@ html.turbolinks-progress-bar::before {
width: 100px;
}
}
.modal-invite-users {
.bootstrap-tagsinput {
min-width: 450px;
}
.org-selector .heading {
margin-top: 15px;
margin-bottom: 5px;
input[type=checkbox] {
vertical-align: middle;
margin: 0;
}
}
}

View file

@ -27,4 +27,8 @@ class Users::InvitationsController < Devise::InvitationsController
resource
end
def invite_users
# TODO
end
end

View file

@ -0,0 +1,129 @@
<%
# How to use this modal:
# 1. Render it in the page (HTML) of your choice
# 2. Add an element (e.g. <a href>) with following attributes:
# * data-trigger="invite-users",
# * data-modal-id="modal-id",
#
# Modal parameters:
# * modal_id: unique id so the JS works if multiple modals are present
# on the same page
# * type:
# * 'invite_to_org' => params: organization
# * 'invite_to_org_with_role' => params: organization, role
# * 'invite',
# * 'invite_with_org_selector',
# * 'invite_with_org_selector_and_role' => params: role
# * organization: invite users to the specified organization
# * role: all users are invited as the specified role
%>
<div
class="modal modal-invite-users"
tabindex="-1"
role="dialog"
aria-labelledby="invite-users-modal-label"
data-id="<%= modal_id %>"
data-role="invite-users-modal"
data-type="<%= type %>"
data-url="<%= invite_users_path %>"
data-backdrop="static"
data-keyboard="false"
<%= "data-organization-id=#{organization.id}" if type.in?(['invite_to_org', 'invite_to_org_with_role']) %>
<%= "data-organization-role=#{role}" if type.in?(['invite_to_org_with_role', 'invite_with_org_selector_and_role']) %>
>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">
<% if type.in?(['invite_to_org', 'invite_to_org_with_role']) %>
<%= t('invite_users.to_org.title', organization: organization.name) %>
<% else %>
<%= t('invite_users.no_org.title') %>
<% end %>
</h4>
</div>
<div class="modal-body">
<div data-role="step-form">
<p>
<% if type.in?(['invite_to_org', 'invite_to_org_with_role']) %>
<%= t('invite_users.to_org.heading', organization: organization.name) %>
<% else %>
<%= t('invite_users.no_org.heading') %>
<% end %>
</p>
<select class="emails-input" multiple data-role="tagsinput" name="emails[]">
</select>
<br />
<em><%= t('invite_users.input_subtitle') %></em>
<% if type.in?(['invite_with_org_selector', 'invite_with_org_selector_and_role']) %>
<% uos = current_user.user_organizations.where(role: UserOrganization.roles[:admin]).joins(:organization) %>
<% if uos.count > 0 %>
<div class="org-selector">
<div class="heading">
<input type="checkbox" data-role="org-selector-checkbox" />
<span><%= t('invite_users.invite_to_org_heading') %></span>
</div>
<%= select_tag(
'organization-select',
options_for_select(
uos.pluck('organizations.name', 'organizations.id')
),
{
class: 'form-control selectpicker',
'data-role' => 'org-selector-dropdown',
disabled: 'disabled'
}
) %>
</div>
<% end %>
<% end %>
</div>
<div data-role="step-results" data-clear="true">
</div>
</div>
<div class="modal-footer">
<div data-role="step-form">
<button type="button" class="btn btn-default" data-dismiss="modal">
<%= t('general.cancel') %>
</button>
<!-- Invite buttons -->
<button type="button" data-role="invite-btn" class="btn btn-primary" disabled="disabled" data-action="invite">
<%= t('invite_users.invite_btn') %>
</button>
<div class="btn-group" data-role="invite-with-role-div">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" data-id="invite-btn" aria-haspopup="true" aria-expanded="false" data-role="invite-with-role-btn" disabled="disabled">
<%= t('invite_users.invite_btn') %>
&nbsp;
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" data-action="invite" data-organization-role="guest">
<%= t("invite_users.invite_guest") %>
</a></li>
<li><a href="#" data-action="invite" data-organization-role="normal_user">
<%= t("invite_users.invite_user") %>
</a></li>
<li><a href="#" data-action="invite" data-organization-role="admin">
<%= t("invite_users.invite_admin") %>
</a></li>
</ul>
</div>
</div>
<div data-role="step-results">
<button type="button" class="btn btn-default" data-dismiss="modal">
<%= t('general.close') %>
</button>
</div>
</div>
</div>
</div>
</div>

View file

@ -59,6 +59,7 @@ Rails.application.config.assets.precompile += %w(assets.js)
Rails.application.config.assets.precompile += %w(comments.js)
Rails.application.config.assets.precompile += %w(projects/show.js)
Rails.application.config.assets.precompile += %w(notifications.js)
Rails.application.config.assets.precompile += %w(users/invite_users_modal.js)
# Libraries needed for Handsontable formulas
Rails.application.config.assets.precompile += %w(lodash.js)

View file

@ -1449,6 +1449,20 @@ en:
head_title: "Edit protocol"
no_keywords: "No keywords"
invite_users:
to_org:
title: "Invite users to team %{organization}"
heading: "Invite more people to team %{organization} and start using sciNote."
no_org:
title: "Invite users to sciNote"
heading: "Invite more people to start using sciNote."
input_subtitle: "Input one or multiple emails, confirm each email with ENTER key."
invite_to_org_heading: "Invite users to my team:"
invite_btn: "Invite user/s"
invite_guest: "as Guest/s"
invite_user: "as Normal user/s"
invite_admin: "as Administrator/s"
time:
formats:
full: "%d.%m.%Y %H:%M"

View file

@ -39,6 +39,11 @@ Rails.application.routes.draw do
get "users/settings/user_organizations/:user_organization_id/destroy_html", to: "users/settings#destroy_user_organization_html", as: "destroy_user_organization_html"
delete "users/settings/user_organizations/:user_organization_id", to: "users/settings#destroy_user_organization", as: "destroy_user_organization"
# Invite users
post 'users/invite',
to: 'users/invitations#invite_users',
as: 'invite_users'
# Notifications
get 'users/:id/recent_notifications',
to: 'user_notifications#recent_notifications',