containers/Admin/UserSettings.js

/* eslint-disable jsx-a11y/control-has-associated-label */
import React, { Component } from 'react';
import { connect } from 'react-redux';

import { getUsers, getRolesList } from '../../selectors/admin';
import {
  getActiveModal,
  checkPermisson,
  getModalData,
  getPagination,
  getUser,
  hasRecord,
  clearFilters,
  getFilterData,
  getSelectedTimezone,
} from '../../selectors/common';
import Pagination from '../../components/Pagination';
import { MODALS, SVG_ICONS, PERMISSIONS } from '../../constants';
import SVGComponent from '../../components/SVG/SVGComponent';

import UserModal from '../../components/MenuItems/Admin/UserModal';
import Filter from '../../components/Filter';
import { getCountryDateTime } from '../../utils/common';
import ConfirmationModal from '../../components/Modals/ConfirmationModal';
import TableNoResult from '../../components/TableNoResult';
import { aClearFilterData } from '../../reducers/cashier';
import { aSetClearFilters, aSetFilters, aSetOpenModal } from '../../reducers/common';
import {
  aRolesInit,
  aSetPagination,
  aUserAdd,
  aUserEditInfo,
  aUserEditRoles,
  aUserEditStatus,
  aUserList,
  aUserRemove,
  aUserResetPass,
} from '../../reducers/actions';

const mapToProps = (state) => ({
  pagination: getPagination(state),
  users: getUsers(state),
  activeModal: getActiveModal(state),
  roles: getRolesList(state),
  checkPermisson: (payload) => checkPermisson(state, payload),
  modalData: getModalData(state),
  currentUser: getUser(state),
  hasRecord: hasRecord(state),
  clearFilters: clearFilters(state),
  filters: getFilterData(state),
  selectedTimezone: getSelectedTimezone(state),
});

const actionsToProps = (dispatch) => ({
  fetchUserList: (payload) => dispatch(aUserList(payload)),
  setOpenModal: (payload) => dispatch(aSetOpenModal(payload)),
  getRoles: (payload) => dispatch(aRolesInit(payload)),
  addUser: (payload) => dispatch(aUserAdd(payload)),
  userResetPass: (payload) => dispatch(aUserResetPass(payload)),
  userRemove: (payload) => dispatch(aUserRemove(payload)),
  userEditStatus: (payload) => dispatch(aUserEditStatus(payload)),
  userEditRoles: (payload) => dispatch(aUserEditRoles(payload)),
  userEditInfo: (payload) => dispatch(aUserEditInfo(payload)),
  setFilterData: (payload) => dispatch(aSetFilters(payload)),
  setPagination: (payload) => dispatch(aSetPagination(payload)),
  setClearFilers: (payload) => dispatch(aSetClearFilters(payload)),
  clearFilterData: (payload) => dispatch(aClearFilterData(payload)),
});

/**
 * @class
 * @property {object} props
 * @property {object} props.pagination Pagination data
 * @property {Array} props.users User data
 * @property {string} props.activeModal Active modal
 * @property {Array} props.roles All roles data
 * @property {boolean} props.checkPermisson Check if user have
 * permission for specific action or view
 * @property {object} props.currentUser Information about the current logged in user
 * @property {object} props.modalData Modal data
 * @property {Function} props.fetchUserList API action to get users list data
 * @property {Function} props.setOpenModal Open modal
 * @property {Function} props.getRoles API action to get roles data
 * @property {Function} props.addUser API action to add new user
 * @property {Function} props.userResetPass  API action to reset user password
 * @property {Function} props.userRemove  API action to remove user
 * @property {Function} props.userEditStatus  API action to edit user status
 * @property {Function} props.userEditRoles API action to edit user's roles
 * @property {Function} props.userEditInfo API action to edit user info
 * @property {Function} props.setFilterData Filter users
 * @property {Function} props.setPagination Set pagination data
 * @property {object} props.filters Filters data
 * @property {Function} props.clearFilterData Clear Filter Data
 */
class UserSettings extends Component {
  constructor(props) {
    super(props);

    /**
     * @member {object}
     * @property {number|null} openUserMenuUserId
     * @property {object|null} operation
     * @property {object} operationUser
     */
    this.state = {
      openUserMenuUserId: null,
      operation: null,
      operationUser: {},
    };

    /**
     * @member {Array}
     * @description Filtering fields settings
     */
    this.filterFields = [
      {
        text: 'Username',
        field: 'filter.username',
      },
      {
        text: 'Email',
        field: 'filter.email',
      },
    ];

    /**
     * @member {object}
     */
    this.filters = props.filters ? { ...props.filters } : {};

    /**
     * @member {boolean}
     */
    this.addPermission = props.checkPermisson(PERMISSIONS.ADMIN_USERS_ADD);
    /**
     * @member {boolean}
     */
    this.enablePermission = props.checkPermisson(PERMISSIONS.ADMIN_USERS_ENABLE);
    /**
     * @member {boolean}
     */
    this.resetPassPermission = props.checkPermisson(PERMISSIONS.ADMIN_USERS_RESET_PASSWORD);
    /**
     * @member {boolean}
     */
    this.editRolesPermission = props.checkPermisson(PERMISSIONS.ADMIN_USERS_ROLES);
    /**
     * @member {boolean}
     */
    this.deletePermission = props.checkPermisson(PERMISSIONS.ADMIN_USERS_DELETE);
    /**
     * @member {boolean}
     */
    this.updateUserPermission = props.checkPermisson(PERMISSIONS.ADMIN_USERS_UPDATE);

    /**
     * @member {boolean}
     */
    this.hasThreeDots =
      this.enablePermission ||
      this.resetPassPermission ||
      this.editRolesPermission ||
      this.updateUserPermission ||
      this.deletePermission;

    /**
     * @member {object}
     * @description Confirmation modal data
     */
    this.confirmationData = {
      REMOVE: {
        heading: 'Remove?',
        title: 'Are you sure you want to remove user: ',
        confirmation: this.userRemove,
      },
      DISABLE: {
        heading: 'Disable?',
        title: 'Are you sure you want to disable user: ',
        confirmation: this.disableUser,
      },
      ENABLE: {
        heading: 'Enable?',
        title: 'Are you sure you want to enable user: ',
        confirmation: this.enableUser,
      },
      RESET: {
        heading: 'Reset password?',
        title: 'Are you sure you want to reset password for user: ',
        confirmation: this.resetPassword,
      },
    };
  }

  /**
   * Get all roles
   *
   * @returns {void}
   */
  componentDidMount() {
    this.props.getRoles({ skipParams: true });
  }

  /**
   * Handle remove user
   *
   * @function
   * @returns {void}
   */
  userRemove = () => {
    this.props.userRemove({
      userId: this.state.operationUser.userId,
      username: this.state.operationUser.username,
    });
    this.closeModal();
  };

  /**
   * Handle disable user
   *
   * @function
   * @returns {void}
   */
  disableUser = () => {
    this.props.userEditStatus({
      userId: this.state.operationUser.userId,
      status: -1,
    });
    this.closeModal();
  };

  /**
   * Handle enable user
   *
   * @function
   * @returns {void}
   */
  enableUser = () => {
    this.props.userEditStatus({
      userId: this.state.operationUser.userId,
      status: 1,
      username: this.state.operationUser.username,
    });
    this.closeModal();
  };

  /**
   * Handle reset password
   *
   * @function
   * @returns {void}
   */
  resetPassword = () => {
    this.props.userResetPass({
      userId: this.state.operationUser.userId,
      username: this.state.operationUser.username,
      email: this.state.operationUser.email,
    });
    this.closeModal();
  };

  /**
   * Handle user menu click
   *
   * @function
   * @param {number} userId
   * @returns {void}
   */
  handleUserMenuClick = (userId) => {
    if (this.state.openUserMenuUserId === userId) {
      this.setState({ openUserMenuUserId: null });
    } else {
      this.setState({ openUserMenuUserId: userId });
    }
  };

  /**
   * Handle user operation click
   *
   * @function
   * @param {object} operation
   * @param {object} user
   * @returns {void}
   */
  handleUserOperationClick = (operation, user) => {
    this.props.setOpenModal({ modal: MODALS.USER_CONFIRM });
    this.setState({
      operation,
      operationUser: user,
      openUserMenuUserId: null,
    });
  };

  /**
   * Handle edit roles
   *
   * @function
   * @param {object} user
   * @returns {void}
   */
  handleEditRoles = (user) => {
    this.setState({
      operationUser: user,
      openUserMenuUserId: null,
    });
    this.props.setOpenModal({ modal: MODALS.USER_EDIT });
  };

  /**
   * Handle edit user information
   *
   * @function
   * @param {object} user
   * @returns {void}
   */
  handleEditUserInfo = (user) => {
    this.setState({
      operationUser: user,
      openUserMenuUserId: null,
    });
    this.props.setOpenModal({ modal: MODALS.USER_INFO_EDIT });
  };

  /**
   * Close modal
   *
   * @function
   * @returns {void}
   */
  closeModal = () => {
    this.props.setOpenModal({ modal: '' });
  };

  /**
   * Open add user modal
   *
   * @function
   * @returns {void}
   */
  openAddUserModal = () => {
    this.props.setOpenModal({ modal: MODALS.USER_ADD });
    this.props.setClearFilers({ filterState: true });
  };

  /**
   * Render user row
   *
   * @function
   * @param {object} user
   * @returns {void}
   */
  renderUserRow = (user) => {
    const openClass = user.userId === this.state.openUserMenuUserId ? ' open active' : '';

    return (
      <tr key={`user${user.userId}`} className={`table-style-row ${openClass}`}>
        <td>{user.userId}</td>
        <td>{user.username}</td>
        <td>{user.name}</td>
        <td>{user.email}</td>
        <td>{getCountryDateTime(user.insertionDate, this.props.selectedTimezone)}</td>
        <td>{user.insertionUser}</td>
        <td>{getCountryDateTime(user.lastLogin, this.props.selectedTimezone)}</td>
        <td className="text-left">
          {user.roles.map((el) => {
            const key = `user-${user.userId}-role-${el.id}`;
            return (
              <div key={key}>
                {el.name}
                {el.status === -1 && <span className="txt-disable">D</span>}
              </div>
            );
          })}
        </td>
        <td className="text-left">{user.status === 1 ? 'Enabled' : 'Disabled'}</td>
        {this.hasThreeDots ? (
          <td className="table-style-icon">
            <SVGComponent
              onClick={this.handleUserMenuClick.bind(this, user.userId)}
              className="icon-xs"
              src={`${SVG_ICONS.utility}#dots`}
            />
            <div className="table-style-option">
              {user.status === 1
                ? this.enablePermission && (
                    <div
                      className="table-style-option-item"
                      onClick={this.handleUserOperationClick.bind(this, this.confirmationData.DISABLE, user)}
                    >
                      Disable
                    </div>
                  )
                : this.enablePermission && (
                    <div
                      className="table-style-option-item"
                      onClick={this.handleUserOperationClick.bind(this, this.confirmationData.ENABLE, user)}
                    >
                      Enable
                    </div>
                  )}
              {this.resetPassPermission && (
                <div
                  className="table-style-option-item"
                  onClick={this.handleUserOperationClick.bind(this, this.confirmationData.RESET, user)}
                >
                  Reset Password
                </div>
              )}
              {this.editRolesPermission && (
                <div className="table-style-option-item" onClick={this.handleEditRoles.bind(this, user)}>
                  Edit Roles
                </div>
              )}
              {this.updateUserPermission && (
                <div className="table-style-option-item" onClick={this.handleEditUserInfo.bind(this, user)}>
                  Edit User
                </div>
              )}
              {this.deletePermission && (
                <div
                  className="table-style-option-item"
                  onClick={this.handleUserOperationClick.bind(this, this.confirmationData.REMOVE, user)}
                >
                  Remove
                </div>
              )}
            </div>
          </td>
        ) : null}
      </tr>
    );
  };

  /**
   * Render modals
   *
   * @function
   * @returns {view|null}
   */
  renderModals = () => {
    switch (this.props.activeModal) {
      case MODALS.USER_ADD:
        return (
          <UserModal
            roles={this.props.roles}
            add
            heading="Add user"
            save={this.props.addUser}
            setOpenModal={this.props.setOpenModal}
          />
        );
      case MODALS.USER_CONFIRM:
        return (
          <ConfirmationModal
            modalData={{
              heading: this.state.operation.heading,
              title: this.state.operation.title,
              additionalMessages: [this.state.operationUser.username],
            }}
            cancel={this.closeModal}
            confirmation={this.state.operation.confirmation}
          />
        );
      case MODALS.USER_EDIT:
        return (
          <UserModal
            roles={this.props.roles}
            user={this.state.operationUser}
            editRoles
            heading="Edit user roles"
            save={this.props.userEditRoles}
            setOpenModal={this.props.setOpenModal}
            currentUserId={this.props.currentUser.userId}
            fetchUserList={this.props.fetchUserList}
          />
        );
      case MODALS.USER_INFO_EDIT:
        return (
          <UserModal
            roles={this.props.roles}
            user={this.state.operationUser}
            editInfo
            heading="Edit user"
            save={this.props.userEditInfo}
            setOpenModal={this.props.setOpenModal}
          />
        );
      default:
        return null;
    }
  };

  /**
   * Render
   *
   * @returns {view}
   */
  render() {
    const isFaded = this.state.openUserMenuUserId !== null;
    return (
      <>
        <div className="user">
          <Filter
            filterFields={this.filterFields}
            info
            setFilterData={this.props.setFilterData}
            search={this.props.fetchUserList}
            initialApiCall
            allowEmpty
            clearFilters={this.props.clearFilters}
            filtersProps={this.props.filters}
            defaultFilter={{}}
            filters={this.filters}
            clearFilterData={this.props.clearFilterData}
            selectedTimezone={this.props.selectedTimezone}
          >
            {this.addPermission && (
              <button id="addUser_filter" type="button" className="btn btn-secondary" onClick={this.openAddUserModal}>
                Add User
              </button>
            )}
          </Filter>

          <div className="table-wrapper">
            <div className="table-mask" />
            <div className="table-responsive">
              <table className="table-style table-s" id="data-table">
                <thead>
                  <tr>
                    <th>ID</th>
                    <th>Username</th>
                    <th>Name</th>
                    <th>Email</th>
                    <th>Creation Date</th>
                    <th>Created By</th>
                    <th>Last Login Dt</th>
                    <th className="text-left">Roles</th>
                    <th className="text-left">Status</th>
                    <th />
                  </tr>
                </thead>
                <tbody>{this.props.users.map((user) => this.renderUserRow(user))}</tbody>
              </table>
              {!this.props.hasRecord && <TableNoResult />}
            </div>
          </div>
          {this.renderModals()}

          {this.props.pagination.page && (
            <Pagination
              {...this.props.pagination}
              paging={this.props.fetchUserList}
              setPagination={this.props.setPagination}
            />
          )}
        </div>
        {isFaded && <div className="overlay-mask bg-grey open" />}
      </>
    );
  }
}

export default connect(mapToProps, actionsToProps)(UserSettings);