components/MenuItems/Admin/UserModal.js

/* eslint-disable sonarjs/no-duplicate-string */
import React, { Component } from 'react';
import { connect } from 'react-redux';
import SVGComponent from '../../SVG/SVGComponent';
import { SVG_ICONS, EDIT_USER_MODAL_MESSAGE, ROLE_STATUS } from '../../../constants';
import validateFields from '../../../utils/validation';
import { aSetClearFilters } from '../../../reducers/common';

/**
 * @module MI-Admin/UserModal
 */

const actionsToProps = (dispatch) => ({
  setClearFilers: (payload) => dispatch(aSetClearFilters(payload)),
});

/**
 * @param roleName
 * @param status
 * @param roleName
 * @param status
 * @param ind
 * @typedef {object} props
 * @property {Array} roles
 * @property {boolean} editRoles
 * @property {boolean} add
 * @property {boolean} editInfo
 * @property {object} [user]
 * @property {string} currentUserId
 * @property {string} heading
 * @property {Function} save
 * @property {Function} setOpenModal
 */
class UserModal extends Component {
  constructor(props) {
    super(props);

    /**
     * @member {object}
     * @property {string} username
     * @property {string} email
     * @property {string} name
     * @property {Array} roles
     * @property {object} errorMgs
     */
    this.state = {
      username: this.props.editInfo ? this.props.user.username : '',
      email: this.props.editInfo ? this.props.user.email : '',
      name: this.props.editInfo ? this.props.user.name : '',
      roles: props.editRoles ? props.user.roles.map((el) => el.id) : [''],
      errorMgs: {},
      dropdownId: null,
    };
  }

  /**
   * Updating state fields
   *
   * @function
   * @param {string} field
   * @param {Event} e
   * @returns {void}
   */
  updateField = (field, e) => {
    const value = e.target.value;
    const change = {};
    change[field] = value;
    this.setState(change);
  };

  /**
   * Handle select
   *
   * @function
   * @param {number} ind
   * @param {number} order
   * @returns {void}
   */
  handleSelect = (ind, order) => {
    const newRoles = this.state.roles.slice(0);
    newRoles[ind] = order;
    this.setState({
      roles: newRoles,
      errorMgs: {},
    });
  };

  /**
   * Handle add role
   *
   * @function
   * @returns {void}
   */
  handleAddRole = () => {
    const newRoles = this.state.roles.slice(0);
    newRoles.push('');
    this.setState({
      roles: newRoles,
      errorMgs: {},
    });
  };

  /**
   * Handle remove role
   *
   * @function
   * @param {numer} ind
   * @returns {void}
   */
  handleRemoveRole = (ind) => {
    const newRoles = this.state.roles.slice(0);
    newRoles.splice(ind, 1);
    this.setState({
      roles: newRoles,
      errorMgs: {},
    });
  };

  /**
   * Handle click on save
   *
   * @function
   * @returns {void}
   */
  handleSave = () => {
    const validationParams = [];
    if (!this.props.editInfo) {
      validationParams.push({
        label: 'Role',
        fieldName: 'role',
        value: this.state.roles.toString().replace(/,/g, ''),
        rules: ['mandatory'],
      });
    }
    if (this.props.add || this.props.editInfo) {
      if (this.props.add) {
        validationParams.push({
          label: 'Username',
          fieldName: 'username',
          value: this.state.username,
          rules: ['mandatory'],
        });
      }
      validationParams.push({
        label: 'Name',
        fieldName: 'name',
        value: this.state.name,
        rules: ['mandatory'],
      });
      validationParams.push({
        label: 'Email',
        fieldName: 'email',
        value: this.state.email,
        rules: ['mandatory', 'regExp'],
        expression: '^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+(?:[a-zA-Z0-9])+@(?:[a-zA-Z0-9]+\\.)+[A-Za-z]+$',
      });
    }
    validateFields(validationParams)
      .then(() => {
        const body = {
          roleIds: this.state.roles.filter((x) => x !== ''),
          username: this.state.username.trim(),
          name: this.state.name.trim(),
          email: this.state.email,
          user: this.props.user,
          callback: this.props.fetchUserList,
        };
        this.props.save(body);
      })
      .catch((errorMgs) => {
        this.setState({ errorMgs });
      });
  };

  /**
   * Close modal
   *
   * @returns {void}
   */
  cancel = () => {
    this.props.setClearFilers({ filterState: false });
    this.props.setOpenModal({ modal: '' });
  };

  /**
   * Render item for dropdown
   *
   * @function
   * @param {number} ind
   * @returns {view}
   */
  renderDropdownItem = (ind) =>
    this.props.roles.map((el) => (
      <div
        className={`dialog__fields-list-item${el.status === ROLE_STATUS.DISABLED ? ' is-disable' : ''}`}
        key={`role-opt-${ind}-${el.roleId}`}
        id={el.roleId}
        onClick={this.handleSelect.bind(this, ind, el.roleId)}
      >
        <span>{el.name}</span>
        {el.status === ROLE_STATUS.DISABLED && <span className="txt"> (disabled)</span>}
      </div>
    ));

  /**
   * Handle Open Dropdown
   *
   * @function
   * @param {number} dropdownId
   * @returns {void}
   */
  handleDropdown = (dropdownId) => {
    if (dropdownId === this.state.dropdownId) {
      this.setState({
        dropdownId: null,
      });
    } else {
      this.setState({
        dropdownId,
      });
    }
  };

  /**
   * Return name of role
   *
   * @function
   * @param {ind} ind
   * @returns {void}
   */
  getRoleName = (ind) => {
    let roleName = 'Select Role';
    this.props.roles.filter((x) => {
      if (this.state.roles[ind] === x.roleId) {
        roleName = x.name;
      }
    });
    return roleName;
  };

  /**
   * Return status of role
   *
   * @function
   * @param {ind} ind
   * @returns {void}
   */
  getStatusRole = (ind) => {
    let status = false;
    this.props.roles.filter((x) => {
      if (this.state.roles[ind] === x.roleId && x.status === ROLE_STATUS.DISABLED) {
        status = true;
      }
    });
    return status;
  };

  /**
   * Render role
   *
   * @function
   * @param {numer} ind
   * @param {boolean} showDelete
   * @returns {view}
   */
  renderRole = (ind, showDelete) => (
    <div className="dialog__row" key={`role-${ind}`} id={ind}>
      <div className="dialog__fields" onClick={() => this.handleDropdown(ind)}>
        <label className={`${this.props.editRoles ? 'style-1' : 'style-2'}`}>Role</label>
        <div className="d-flex align-items-center position-relative">
          <div className={`dialog__fields-select${this.state.dropdownId === ind ? ' open' : ''}`}>
            <span>{this.getRoleName(ind)}</span>
            {this.getStatusRole(ind) && <span className="txt"> (disabled)</span>}
          </div>
          <div className="dialog__fields-dropdown">
            <div className="dialog__fields-list">{this.renderDropdownItem(ind)}</div>
          </div>
          {showDelete && (
            <div className="dialog__icon">
              <SVGComponent
                onClick={this.handleRemoveRole.bind(this, ind)}
                className="icon-xxs"
                src={`${SVG_ICONS.utility}#bin`}
              />
            </div>
          )}
        </div>
        {this.state.errorMgs.role}
      </div>
    </div>
  );

  /**
   * Render user info inputs for add user modal
   *
   * @function
   * @returns {view}
   */
  renderUserInfo = () => (
    <>
      <div className="dialog__row">
        <div className="dialog__fields">
          <label className="style-2">Username</label>
          {this.props.editInfo ? (
            <div className="dialog__detail">{this.state.username}</div>
          ) : (
            <input
              id="username_userModal"
              type="text"
              className="form-control"
              value={this.state.username}
              onChange={this.updateField.bind(this, 'username')}
            />
          )}
          {this.state.errorMgs.username}
        </div>
      </div>
      <div className="dialog__row">
        <div className="dialog__fields">
          <label className="style-2">Name</label>
          <input
            id="name_userModal"
            type="text"
            className="form-control"
            value={this.state.name}
            onChange={this.updateField.bind(this, 'name')}
          />
          {this.state.errorMgs.name}
        </div>
      </div>
      <div className="dialog__row">
        <div className="dialog__fields">
          <label className="style-2">Email</label>
          <input
            id="email_userModal"
            type="email"
            className="form-control"
            value={this.state.email}
            onChange={this.updateField.bind(this, 'email')}
          />
          {this.state.errorMgs.email}
        </div>
      </div>
      {!this.props.editInfo && this.renderRole(0, false)}
    </>
  );

  /**
   * Render user info for edit user modal
   *
   * @function
   * @returns {view}
   */
  renderEditUserInfo = () => (
    <div className="dialog__info">
      <div className="dialog_info-left">
        <div className="dialog__info-title">Username</div>
        <div className="dialog__info-name">{this.props.user.username}</div>
      </div>
      <div className="dialog__info-right">
        <div className="dialog__info-title">Email</div>
        <div className="dialog__info-email">{this.props.user.email}</div>
      </div>
    </div>
  );

  /**
   * Render message for modal
   *
   * @function
   * @returns {view}
   */
  renderModalMessage = () => {
    if (this.props.currentUserId === this.props.user.userId) {
      return <span>{EDIT_USER_MODAL_MESSAGE.sameUser}</span>;
    }
    return <span>{EDIT_USER_MODAL_MESSAGE.differentUser}</span>;
  };

  /**
   * Render
   *
   * @returns {view}
   */
  render() {
    return (
      <div className={`dialog open ${this.props.editRoles && 'drm'}`} id="add-user">
        <div className="p-20">
          <div className="dialog__heading">
            <span className="dialog-title">{this.props.heading}</span>
            <SVGComponent onClick={this.cancel} className="icon-xxs dialog__close" src={`${SVG_ICONS.utility}#close`} />
          </div>
        </div>
        {this.props.editRoles && this.renderEditUserInfo()}
        <div className="dialog__wrapper">
          {!this.props.editRoles && this.renderUserInfo()}
          {!this.props.editInfo &&
            this.state.roles.map((el, ind) => {
              // skip first
              if (ind === 0 && this.props.add) return null;
              return this.renderRole(ind, this.props.add || this.state.roles.length > 1);
            })}
        </div>
        {!this.props.editInfo && (
          <div className="dialog__button" onClick={this.handleAddRole} id="addRole_userModal">
            <span>+</span>
            Add role
          </div>
        )}
        <div className="p-20">
          <div className="dialog__button-wrapper flex-wrap">
            <div className="dialog__button-wrapper-txt mb-3">
              {this.props.user && !this.props.editInfo && this.renderModalMessage()}
            </div>
            <button id="cancelBtn_userModal" type="button" className="btn btn-secondary" onClick={this.cancel}>
              Cancel
            </button>
            <button id="saveBtn_userModal" type="button" className="btn btn-primary ml-10" onClick={this.handleSave}>
              Save
            </button>
          </div>
        </div>
      </div>
    );
  }
}

export default connect(null, actionsToProps)(UserModal);