/* eslint-disable react/no-array-index-key */
import React, { Component } from 'react';
import SVGComponent from '../../SVG/SVGComponent';
import { SVG_ICONS } from '../../../constants';
import validateFields from '../../../utils/validation';
/**
* @module MI-Admin/RoleModal
*/
/**
* @typedef {object} props
* @property {Array} permissions
* @property {Array} rolePermissions
* @property {number} selectedRoleId
* @property {object} role
* @property {boolean} isEditingRole
* @property {boolean} isAddNewRole
* @property {Function} saveNewRole
* @property {Function} saveEditRole
* @property {Function} getRolePermissions
* @property {Function} closeRoleModal
*/
export default class RoleModal extends Component {
constructor(props) {
super(props);
/**
* @member {object}
* @property {string} name
* @property {string} description
* @property {Array} assignedPermissions
* @property {Array} availablePermissions
* @property {number} selectedAssignedIndex
* @property {number} selectedAvailableIndex
* @property {string} assignedFilterText
* @property {string} availableFilterText
* @property {object} errorMgs
*/
this.state = {
name: props.role.name,
description: props.role.description,
assignedPermissions: [],
availablePermissions: props.permissions,
selectedAssignedIndex: 0,
selectedAvailableIndex: 0,
assignedFilterText: '',
availableFilterText: '',
errorMgs: {},
};
// COMPONENT WILL MOUNT
// Get permissions for selected role
if (props.isEditingRole) {
props.getRolePermissions({ roleId: props.role.roleId });
}
}
/**
* Checks if role permissions is fetch when editing
*
* @function
* @param {object} prevProps Previous props
* @returns {void}
*/
componentDidUpdate(prevProps) {
if (
this.props.isEditingRole &&
prevProps.selectedRoleId === null &&
this.props.selectedRoleId === this.props.role.roleId
) {
this.setState({
assignedPermissions: this.props.rolePermissions,
availablePermissions: this.permissionDifference(this.props.permissions, this.props.rolePermissions),
});
}
}
/**
* Calculate difference between all permissions and assigned
*
* @function
* @param {Array} all All perrmisions
* @param {Array} assigned perrmissions
* @returns {Array} Difference of all and assigned permissions
*/
permissionDifference = (all, assigned) => all.filter((permission) => !this.inArray(assigned, permission));
/**
* Check if permission is in list
*
* @function
* @param {list} permissionList list of permissions
* @param {object} permissison permissison object
* @returns {boolean}
*/
inArray = (permissionList, permissison) =>
permissionList.findIndex((assigned) => assigned.permissionId === permissison.permissionId) !== -1;
/**
* Move permission to assigned or to available
*
* @function
* @returns {void}
*/
addPermissionToAssigned = () => {
const permission = this.getAvailablePermissions()[this.state.selectedAvailableIndex];
if (permission) {
const newAssignedPermissions = [...this.state.assignedPermissions];
newAssignedPermissions.push(permission);
newAssignedPermissions.sort((p1, p2) => (p1.name > p2.name ? 1 : 0));
const newAvailablePermissions = this.permissionDifference(this.props.permissions, newAssignedPermissions);
let selectedAvailableIndex = this.state.selectedAvailableIndex;
if (selectedAvailableIndex && !this.getAvailablePermissions(newAvailablePermissions)[selectedAvailableIndex]) {
selectedAvailableIndex -= 1;
}
this.setState({
assignedPermissions: newAssignedPermissions,
availablePermissions: newAvailablePermissions,
selectedAvailableIndex,
});
}
};
/**
* Remove permission from assigned
*
* @function
* @returns {void}
*/
removeFromAssingned = () => {
const permission = this.getAssignedPermissions()[this.state.selectedAssignedIndex];
if (permission) {
let newAssignedPermissions = [...this.state.assignedPermissions];
newAssignedPermissions = newAssignedPermissions.filter((p) => p.permissionId !== permission.permissionId);
const newAvailablePermissions = this.permissionDifference(this.props.permissions, newAssignedPermissions);
let selectedAssignedIndex = this.state.selectedAssignedIndex;
if (selectedAssignedIndex && !this.getAssignedPermissions(newAssignedPermissions)[selectedAssignedIndex]) {
selectedAssignedIndex -= 1;
}
this.setState({
assignedPermissions: newAssignedPermissions,
availablePermissions: newAvailablePermissions,
selectedAssignedIndex,
});
}
};
/**
* Handle form change
*
* @param {string} key
* @param {Event} e
* @function
* @returns {void}
*/
handleFormChange = (key, e) => {
const value = e.target.value;
const newStateObj = {
selectedAssignedIndex: 0,
selectedAvailableIndex: 0,
};
newStateObj[key] = value;
this.setState(newStateObj);
};
/**
* Save changes
*
* @function
* @returns {void}
*/
saveProcess = () => {
if (this.props.isAddNewRole === true) {
this.props.saveNewRole({
name: this.state.name,
description: this.state.description,
permissionIds: this.state.assignedPermissions.map((item) => item.permissionId),
});
} else {
this.props.saveEditRole({
roleId: this.props.role.roleId,
name: this.state.name,
description: this.state.description,
permissionIds: this.state.assignedPermissions.map((item) => item.permissionId),
});
}
this.closeDialog();
};
/**
* Validate fields before save
*
* @function
* @returns {void}
*/
validateFields = () => {
const validationParams = [
{
label: 'Name',
fieldName: 'name',
value: this.state.name,
rules: ['mandatory'],
},
{
label: 'Description',
fieldName: 'description',
value: this.state.description,
rules: ['mandatory'],
},
{
label: 'Assigned permission',
fieldName: 'permissionIds',
value: this.state.assignedPermissions.length,
rules: ['mandatory'],
},
];
validateFields(validationParams)
.then(() => {
this.saveProcess();
})
.catch((errorMgs) => {
this.setState({ errorMgs });
});
};
/**
* Close dialog
*
* @function
* @returns {void}
*/
closeDialog = () => {
this.props.closeRoleModal();
};
/**
* Select row in assigned list
*
* @function
* @param {number} index Permision id
* @returns {void}
*/
setAssignedSelected = (index) => {
this.setState({ selectedAssignedIndex: index });
};
/**
* Select row in available list
*
* @function
* @param {number} index Permision id
* @returns {void}
*/
setAvailableSelected = (index) => {
this.setState({ selectedAvailableIndex: index });
};
/**
* Filter permission
*
* @function
* @param {Array} roles roles
* @param {string} serchText Search text
* @returns {void}
*/
getFilteredPermissions = (roles, serchText) => roles.filter((perm) => this.checkForMatch(perm.name, serchText));
/**
* Get assigned permission
*
* @function
* @param {object} permission roles
* @returns {void}
*/
getAssignedPermissions = (permission) =>
this.getFilteredPermissions(permission || this.state.assignedPermissions, this.state.assignedFilterText);
/**
* Get available permission
*
* @function
* @param {object} permission roles
* @returns {void}
*/
getAvailablePermissions = (permission) =>
this.getFilteredPermissions(permission || this.state.availablePermissions, this.state.availableFilterText);
/**
* Check for string in string (str2 in str1)
*
* @function
* @param {string} str1 First string
* @param {string} str2 Second string
* @returns {boolean}
*/
checkForMatch = (str1, str2) => str1.toLowerCase().indexOf(str2.toLowerCase()) !== -1;
/**
* Render
*
* @returns {view}
*/
render() {
return (
<div className="dialog dialog--md open">
<div className="p-20">
<div className="dialog__heading">
<span className="dialog-title">{this.props.isEditingRole === true ? 'Edit Role' : 'Add Role'}</span>
<SVGComponent
className="icon-xxs dialog__close"
onClick={this.closeDialog}
src={`${SVG_ICONS.utility}#close`}
/>
</div>
</div>
<div className="dialog__row align-items-start">
<div className="dialog__fields mr-20">
<label className="style-2">Name</label>
<input
id="name_roleModal"
type="text"
className="form-control"
placeholder="-"
value={this.state.name}
onChange={this.handleFormChange.bind(this, 'name')}
/>
{this.state.errorMgs.name}
</div>
<div className="dialog__fields">
<label className="style-2">Description</label>
<input
id="description_roleModal"
type="text"
className="form-control"
placeholder="-"
value={this.state.description}
onChange={this.handleFormChange.bind(this, 'description')}
/>
{this.state.errorMgs.description}
</div>
</div>
<div className="p-20">
<div className="dialog__roles">
<div className="dialog__roles-wrapper">
<h3>Assigned Permissions</h3>
<div className="dialog__fields">
<input
id="assignedFilterText_roleModal"
type="text"
className="form-control"
value={this.state.assignedFilterText}
onChange={this.handleFormChange.bind(this, 'assignedFilterText')}
/>
<i className="icon-search" />
</div>
{this.state.errorMgs.permissionIds}
<ul className="dialog__list" id="assign-list">
{this.getAssignedPermissions().map((permission, index) => (
<li
key={`asigned-${index}`}
className={`dialog__list-item ${this.state.selectedAssignedIndex === index ? 'active' : ''}`}
onClick={this.setAssignedSelected.bind(this, index)}
>
{permission.name}
</li>
))}
</ul>
</div>
<div className="dialog__switch-wrap">
<div className="dialog__switch">
<div className="remove-arrow" onClick={this.removeFromAssingned}>
<SVGComponent className="icon-xs" src={`${SVG_ICONS.switchArrowIcons}#f-arrow`} />
</div>
<div className="assign-arrow mt-20" onClick={this.addPermissionToAssigned}>
<SVGComponent className="icon-xs" src={`${SVG_ICONS.switchArrowIcons}#b-arrow`} />
</div>
</div>
</div>
<div className="dialog__roles-wrapper">
<h3>Available Permissions</h3>
<div className="dialog__fields">
<input
id="availableFilterText_roleModal"
type="text"
className="form-control"
value={this.state.availableFilterText}
onChange={this.handleFormChange.bind(this, 'availableFilterText')}
/>
<i className="icon-search" />
</div>
<ul className="dialog__list" id="available-list">
{this.getAvailablePermissions().map((permission, index) => (
<li
key={`avail-${index}`}
className={`dialog__list-item ${this.state.selectedAvailableIndex === index ? 'active' : ''}`}
onClick={this.setAvailableSelected.bind(this, index)}
>
{permission.name}
</li>
))}
</ul>
</div>
</div>
</div>
<div className="p-20">
<div className="dialog__button-wrapper">
<button id="cancelBtn_roleModal" className="btn btn-secondary" onClick={this.closeDialog} type="button">
Cancel
</button>
<button
id="saveBtn_roleModal"
className="btn btn-primary ml-10"
onClick={this.validateFields}
type="submit"
>
Save
</button>
</div>
</div>
</div>
);
}
}