asked on
<form id="user-form" class="needs-validation" method="post" action="/profile/save" novalidate>
...
<div class="password-wrapper">
<button type="button" class="btn btn-primary btn-change-password"><i class="fas fa-fw fa-key"></i> Change Password</button>
<div class="password-template d-none">
<div class="row">
<div class="col-lg-12">
To change your password, begin by entering your current password first...<br><br>
<div class="md-form">
<input type="password" id="current-password" name="current_password" class="form-control" value="">
<label for="current_password"><a id="expose-current" href="#" style="cursor:text;" tabindex="-1">Current Password</a></label>
</div>
</div>
</div>
<!-- new row -->
<div class="row">
<div class="col-lg-6" style="margin-top:-25px;">
<div class="md-form">
<input type="password" id="user-password" name="user[password]" class="form-control" required />
<label for="user-password"><a id="exposure" href="#" style="cursor:text;" tabindex="-1">Password*</a></label>
</div>
</div>
<div class="col-lg-6" style="margin-top:-25px;">
<div class="md-form">
<input type="password" id="user-confirm" class="form-control" required />
<label for="user-password">Confirm*</label>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div style="font-size:9pt; background-color:#3d5fb5; border-radius:10pt; width:90%; margin:auto; height:auto; padding:5px; text-align:center; color:#fff;">Hover over the "Password" and "Current Password" labels to see the actual characters that you have inputted.</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="form-group">
<label> </label><br />
<button type="submit" class="btn btn-primary save"><i class="fas fa-fw fa-key"></i> Change Password</button>
<button type="button" class="btn btn-danger btn-cancel-password">Cancel</button>
</div>
</div>
</div><!--end of row -->
<p>Please ensure that your password meets the following requirements:</p>
<ul class="password-requirements">
<li data-reg="upper">At least 1 uppercase letter.</li>
<li data-reg="lower">At least 1 lowercase letter.</li>
<li data-reg="number">At least 1 number.</li>
<li data-reg="special">At least 1 of the following special characters: !@#$%^&*</li>
<li data-reg="total">At least 8 total characters.</li>
</ul>
</div><!-- end of password-wrapper -->
...
<button type="submit" id="btn-save" class="btn btn-success"><i class="fas fa-fw fa-check"></i> Save</button>
</form>
/*
HOW TO USE:
To Show: $(window).trigger('user-form-show', ['userId']);
To Hide: $(window).trigger('user-form-hide');
On Complete:
$(window).on('user-form-complete', function(e, data){
console.log('Form Data: ', data);
});
Be aware that any reference to a specific id on this page will most likely have to be identified in the context of "$form." Since it's not a part of the DOM, but it's being generated dynamically, you're going to have to be more specific that you might otherwise be normally. For example, the code that changes the "user-password" field from "password" are triggered on the "user-from.html.twig" file using "<label for="user-password"><a id="exposure" href="#" style="cursor:text;" tabindex="-1">Passwords*</a></label>." For the system to "see" the "exposure" id, I had to write it like "$form.on('mouseover', '#exposure', function(e){."
*/
$(document).ready(function(){
$("#chk-user-active").on('change', function () {
$('#user-active').val(this.checked);
});
var $uModal = $('#modal-user-form'),
$form = $('#user-form'),
$passwordButton = $form.find('.btn-change-password').clone(),
$passwordForm = $form.find('.password-template').clone().removeClass('d-none'),
data = [],
loadedUserId = '',
passwordRegex = {
upper: /[A-Z]{1,}/,
lower: /[a-z]{1,}/,
number: /[0-9]{1,}/,
special: /[\!\@\#\$\%\^\&\*]{1,}/,
total: /.{8,}/
};
$form.find('.field-phone').mask('000-000-0000');
$form.find('.password-template').remove();
$(window).on('user-form-show', function(e, userId, opts){
// prep the modal
$uModal.find('.loading').show();
$uModal.find('.main').hide();
// show the modal loading screen
$.magnificPopup.open({
alignTop: true,
items: {
src: $uModal, // can be a HTML string, jQuery object, or CSS selector
type: 'inline'
}
});
// clear the cached data
data = {};
// clear the form from any previous data
clearForm();
// load the data if a valid id is provided
if (typeof userId != 'undefined' && userId != 'new') {
loadFormData(userId);
} else {
// set the id for a new user
loadedUserId = 'new';
// load drag & drop members
teamDragula(userId);
$form.find('#user-role').attr('data-user-id', loadedUserId);
// force the password fields
$form.find('.btn-change-password').replaceWith( $passwordForm.clone() );
$form.find('.btn-cancel-password').closest('.col').remove();
// show the form
$uModal.find('.loading').hide();
$uModal.find('.main').show();
}
});
$(window).on('user-form-hide', function(){
$.magnificPopup.close();
});
$form.on('submit', function (e) {
console.log("here");
let teamArray = [];
$form.find('#drag-team').find('a').each(function () {
let uid = $(this).attr('data-user-id');
if (uid) {teamArray.push(uid);}
});
teamArray = $.unique(teamArray);
$form.find('#user-team').val(JSON.stringify(teamArray));
$form.find('#user-avatar').val() ? $form.find('#user-avatar').val() : $form.find('#user-avatar').val('https://ui-avatars.com/api/?name=' + $form.find('#user-first-name').val() + '%20' + $form.find('#user-last-name').val()+'&background=33b5e5&size=200&color=000000');
var $f = $(this),
$btn = $f.find('button[type="submit"]'),
html = $btn.html(),
formData = $f.serialize(),
route = (loadedUserId !== '') ? $form.attr('action') + '/' + loadedUserId : $form.attr('action');
// include unchecked checkboxes. use filter to only include unchecked boxes.
$.each($('.permission-section input[type=checkbox]').filter(function (idx) {
return $(this).prop('checked') === false;
}),
function (idx, el) {
// attach matched element names to the formData with a chosen value.
formData += '&' + $(el).attr('name') + '=' + false;
}
);
e.preventDefault();
e.stopPropagation();
$f.addClass('was-validated');
if ($f[0].checkValidity() === false) {
addMsg('Please check the highlighted fields!');
return false;
}
$btn.html('<i class="fas fa-fw fa-sync-alt fa-spin"></i> Saving...');
// validate the form and save
$.post(route, formData, function(resp){
if (resp.error) {
clearMsg();
addMsg(resp.msg);
return false;
}
// finish up
$(window).trigger('user-form-hide');
$(window).trigger('user-form-complete', [formData]);
}, 'json').fail(function(){
clearMsg();
addMsg('An unexpected error was encountered while trying to process your request. Please try again.');
}).always(function(){
$btn.html(html);
});
});
$form.on('click', '.btn-change-password', function(){
$(this).replaceWith( $passwordForm.clone() );
});
$form.on('click', '.btn-cancel-password', function(){
$(this).closest('.password-template').replaceWith( $passwordButton.clone() );
});
$form.on('keyup', '#user-password', function(e){
for (var k in passwordRegex) {
if ( !passwordRegex[k].test(this.value) ) {
$form.find('ul.password-requirements > li[data-reg="'+k+'"]').removeClass('text-success').addClass('text-danger');
} else {
$form.find('ul.password-requirements > li[data-reg="'+k+'"]').removeClass('text-danger').addClass('text-success');
}
}
});
$uModal.on('click', '#user-form-cancel', function(){
$(window).trigger('user-form-hide');
});
var reportsTo=dragula({
revertOnSpill: true
}).on('drop', function (el, target, source, sibling) {
// something goes here
});
$form.find('.dragula').each(function (i) {
reportsTo.containers.push(this);
});
function loadFormData(userId) {
$.get('/users/' + userId, {}, function(resp){
if (resp.error) {
$(window).trigger('user-form-hide');
return CAMS.alert('Error', resp.msg);
}
// deconstruct from ease of use
var u = resp.data,
$sRow, html, file;
// set the id for saving
loadedUserId = userId;
// load the form
$form.find('#user-first-name').val( u.firstName );
$form.find('#user-last-name').val( u.lastName );
$form.find('#user-email').val( u.email );
$form.find('#user-mobile').val( (typeof u.mobile != 'undefined') ? u.mobile : '' );
$form.find('#user-settings-timezone').val(u.settings.timezone);
let avtrSrc = '/assets/images/upload-avatar.png';
if (typeof u.avatar != 'undefined') {
if (u.avatar.length > 0) {
$form.find('.avatar-picker').find('img').attr('src', u.avatar);
}
}
$form.find('#user-avatar').val(u.avatar);
$form.find('#user-signature').val(u.signature);
if (typeof u.signature != 'undefined') {
$form.find('.signature-link').html('<img src="' + u.signature + '"/>');
} else {
$form.find('.signature-link').html('<span>______________</span>');
}
$form.find('#user-active').val(u.active);
if (u.active == true) {
$form.find('#chk-user-active').prop('checked',true);
} else {
$form.find('#chk-user-active').prop('checked', false);
}
if (typeof u.role != 'undefined') {
rolePermissions(u.role, u.permissions);
$form.find('#user-role').attr('data-user-id', userId);
$form.find('#user-role').val(u.role);
teamDragula(userId, u.role);
}
if (typeof $form.find('#user-account') != 'undefined') {
$form.find('#user-account').val(u.account);
}
// show the form
$uModal.find('.loading').hide();
$uModal.find('.main').show();
}, 'json').fail(function(){
$(window).trigger('user-form-hide');
addMsg('An unexpected error was encountered while trying to load your user. Please refresh the page to try again.');
});
}
function clearForm() {
clearMsg();
$form.removeClass('was-validated');
$form.find('input[type!="hidden"]').val('');
$form.find('.password-wrapper').empty().append($passwordButton.clone());
$form.find('.avatar-picker').find('img').attr('src', '/assets/images/upload-avatar.png');
$form.find('.signature-link').html('<span>______________</span>');
$form.find('#user-avatar').val('');//hidden field
$form.find('#user-signature').val('');//hidden field
$form.find('#user-active').prop('checked', false);
$form.find('#user-role').val('Sales Representative');
rolePermissions('Sales Representative');
}
function addMsg(txt, type) {
type = (typeof type == 'undefined') ? 'danger' : type;
$form.find('.user-messages').append('<div class="alert alert-'+type+'">'+txt+'</div>');
}
function clearMsg() {
$form.find('.user-messages').empty();
}
$('#modal-user-form').find('#user-role').on('change', function () {
teamDragula($(this).attr('data-user-id'),$(this).val());
rolePermissions($(this).val());
});
function teamDragula(userId, role = 'Sales Representative') {
let teamTitle = '', availableTitle = '', roleMember = '',
$dragDropSection = $form.find('.team-dragula');
$dragDropSection.html('Please wait...');
if (role == 'Sales Manager') {
teamTitle='Team';
availableTitle = 'Members';
roleMember = 'Sales Representative';
} else {
teamTitle='Reports to';
availableTitle = 'Managers';
roleMember = 'Sales Manager';
}
$dragDropSection.html('<div class="col-6 col-small-12 animated zoomIn">'+
'<h3 class="team-title">'+teamTitle+'</h3><hr />'+
'<div class="dragula" id="drag-team" style="height: 100px; border: 2px dashed #eef0f3; overflow: auto; min-height: 100px; cursor:grab;"></div>'+
'<div class="text-muted"><small>Drag available users avatar and Drop into above to <span class="text-success">ADD</span>. Drag avatar & Drop on available members to <span class="text-danger">REMOVE</span>.</small></div>'+
'</div>' +
'<div class="col-2 col-small-12"></div>' +
'<div class="col-4 col-small-12 animated zoomIn">' +
'<h3>Available <span class="available-title">'+availableTitle+'</span></h3><hr />'+
'<div class="scrollbar-macosx drag-avb-col" style="height: 100px; border: 2px dashed #eef0f3; overflow: auto; min-height: 100px; cursor:grab;"><div class="dragula" id="drag-members" style="cursor:grab;"></div></div>'+
'</div>');
let $team = $form.find('#drag-team'), $members = $form.find('#drag-members');
$team.html('Loading...');
$members.html('Loading...');
$.post('/users/team/' + userId, { role: role }, function (resp) {
if (resp.error) {
$(window).trigger('user-form-hide');
return CAMS.alert('Error', resp.msg);
}
// deconstruct from ease of use
var u = resp.data;
// load the members available
$members.html('');
u.members.forEach((user) => {
user.avatar = user.avatar ? user.avatar : 'https://ui-avatars.com/api/?name=' + user.firstName + ' ' + user.lastName + '&background=' + getRandomColor() + '&size=200&color=000000';
$members.append(
'<a href="javascript:void(0);" data-user-id="' + user._id + '" data-toggle="tooltip" title="' + user.firstName + ' ' + user.lastName + '" style="cursor:grab;">' +
'<img src="' + user.avatar + '" title="' + user.firstName + ' ' + user.lastName + '" class="rounded-circle m-1" width="32px"/></a>'
);
});
// load the team
$team.html('');
u.team.forEach((user) => {
user.avatar = user.avatar ? user.avatar : 'https://ui-avatars.com/api/?name=' + user.firstName + ' ' + user.lastName + '&background=' + getRandomColor() + '&size=200&color=000000';
$team.append(
'<a href="javascript:void(0);" data-user-id="' + user._id + '" data-toggle="tooltip" title="' + user.firstName + ' ' + user.lastName + '" style="cursor:grab;">' +
'<img src="' + user.avatar + '" title="' + user.firstName + ' ' + user.lastName + '" class="rounded-circle m-1" width="32px" style="border: 1px solid #c1c1c1;"/></a>'
);
$members.find('a[data-user-id="' + user._id + '"]').remove();
});
var reportsTo = dragula({
revertOnSpill: true
}).on('drop', function (el, target, source, sibling) {
// something goes here
});
$form.find('.dragula').each(function (i) {
reportsTo.containers.push(this);
});
//$('[data-toggle="tooltip"]').tooltip(); // Not working here
}, 'json').fail(function () {
$(window).trigger('user-form-hide');
addMsg('An unexpected error was encountered while trying to load your user. Please refresh the page to try again.');
});
}
$('.permission-section').find('input[type="checkbox"]').on('change', function () {
$(this).val($(this).prop('checked'));
});
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function rolePermissions(role, permissions = {}) {
$.get('/account-management/permissions/roles/' + role, function (res) {
if (res.error) { CAMS.alert('Error', res.msg, 'error'); }
let perns = typeof permissions.dashboard != 'undefined' ? permissions : res.data.permissions;
$.each(perns, function (key, value) {
$.each(value, function (k, v) {
let elmId = 'user-permissions-' + key + '-' + k;
let chkElm = $('#modal-user-form').find('#' + elmId);
let lblElm = $('#modal-user-form').find('label[for="' + elmId + '"]');
if (chkElm) {
chkElm.prop('checked', v);
chkElm.val(v);
$('.permission-section').fadeIn(1, function () {
lblElm.addClass('animated zoomIn');
}).delay(10).show(0, function () {
lblElm.removeClass('animated zoomIn');
});
}
});
});
});
}
$form.on('mouseover', '#exposure', function(e){
e.preventDefault();
$form.find('#user-password').attr('type', 'text');
$form.find('#user-confirm').attr('type', 'text');
});
$form.on('mouseout', '#exposure', function(e){
e.preventDefault();
$form.find('#user-password').attr('type', 'password');
$form.find('#user-confirm').attr('type', 'password');
});
});