containers/Bonus/PointSettings.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

import { getCurrency, checkPermisson, getActiveModal, getModalData, getNavigatedLink } from '../../selectors/common';
import { getPointSettings, getRanks } from '../../selectors/bonus';
import EditableTable from '../../components/MenuItems/Bonus/EditableTable';
import { CONFIRM_MODAL_CONTENT, MENU_ITEMS, MODALS, PERMISSIONS } from '../../constants';
import { parseDecimal } from '../../utils/common';
import ConfirmationModal from '../../components/Modals/ConfirmationModal';
import { aSetNavigationInfo, aSetOpenModal } from '../../reducers/common';
import { aGetPointSettings, aSavePointSettings } from '../../reducers/bonus';
import { withRouterHooks } from '../../utils/router';

const mapToProps = (state) => ({
  currency: getCurrency(state),
  pointSettings: getPointSettings(state),
  ranks: getRanks(state),
  checkPermisson: (payload) => checkPermisson(state, payload),
  activeModal: getActiveModal(state),
  modalData: getModalData(state),
  nextNavigationLink: getNavigatedLink(state),
});

const actionsToProps = (dispatch) => ({
  getPointSettings: (payload) => dispatch(aGetPointSettings(payload)),
  savePointSettings: (payload) => dispatch(aSavePointSettings(payload)),
  setOpenModal: (payload) => dispatch(aSetOpenModal(payload)),
  setNavigationInfo: (payload) => dispatch(aSetNavigationInfo(payload)),
});

/**
 * @class
 * @property {object} props
 * @property {Array} props.pointSettings All point settings data
 * @property {Array} props.currency Currency sign
 * @property {Array} props.ranks All ranks
 * @property {boolean} props.checkPermisson Check if user have permission to edit page
 * @property {Function} props.getPointSettings Call API for point settings
 * @property {Function} props.savePointSettings Call API to save changes
 * @property {Function} props.setOpenModal Open modal
 * @property {object} props.nextNavigationLink link for navigation
 * @property {Function} props.setNavigationInfo set navigation info for unsaved data
 */
class PointSettings extends Component {
  constructor(props) {
    super(props);
    /**
     * @member {object}
     * @property {boolean} rerender
     */
    this.state = {
      rerender: false,
      pointSettings: null,
    };
    /**
     * @member {Array}
     */
    this.fields = null;

    /**
     * @member {boolean}
     */
    this.edit = props.checkPermisson(PERMISSIONS.POINT_SETTINGS_EDIT);
  }

  /**
   * Get point settings
   *
   * @returns {void}
   */
  componentDidMount() {
    this.props.getPointSettings();
  }

  /**
   * Set table heading
   *
   * @param {object} prevProps
   * @returns {void}
   */
  componentDidUpdate(prevProps) {
    if (this.props.ranks && this.props.pointSettings && !this.fields) {
      this.fields = [
        {
          label: '',
          field: 'selectionIndex',
          isNumber: true,
          getValue: (bonus, field) => bonus[field],
        },
      ];
      this.props.ranks.map((rank) => {
        this.fields.push({
          label: rank.rankLabel,
          field: rank.rankID,
          isNumber: true,
          isEditable: true,
          getValue: (bonus, field) => parseDecimal(bonus[field], 100),
        });
      });
      // eslint-disable-next-line react/no-did-update-set-state
      this.setState({
        rerender: !this.state.rerender,
      });
    }
    if (this.props?.pointSettings?.length && this.props.pointSettings !== prevProps.pointSettings) {
      const tableRows = [];
      const keys = Object.keys(this.props.pointSettings[0]);
      keys.forEach((key, i) => {
        if (!Number.isNaN(parseInt(key))) {
          const tempObj = {};
          this.props.pointSettings.map((row, j) => {
            if (key !== 'selectionIndex') {
              tempObj[j + 1] = row[i + 1];
            }
          });
          tempObj.selectionIndex = i + 1;
          tableRows.push(tempObj);
        }
      });
      this.setState({ pointSettings: tableRows });
    }
  }

  /**
   * Call API to save data
   *
   * @function
   * @returns {void}
   */
  save = () => {
    const pointSettings = {};
    const keys = Object.keys(this.state.table[0]);
    keys.forEach((key, i) => {
      const tempObj = {};
      this.state.table.map((row, j) => {
        if (!Number.isNaN(parseInt(row[i]))) {
          tempObj[j + 1] = row[i - 0] / 100;
        }
      });
      if (Object.keys(tempObj).length > 0) {
        if (Number.isNaN(key - 1)) {
          pointSettings[keys.length - 2] = tempObj;
        } else {
          pointSettings[key - 1] = tempObj;
        }
      }
    });
    this.fields = null;
    this.props.savePointSettings({ pointSettings });
    this.editableTable.clearChanges(true);
  };

  /**
   * close modal and navigate
   *
   * @returns {void}
   */
  unsavedNavigation = () => {
    this.props.setOpenModal({ modal: '' });
    this.props.navigate(this.props.nextNavigationLink);
  };

  /**
   * set table info
   *
   * @param {Array} data
   * @returns {void}
   */
  setTableInfo = (data) => {
    this.setState({ table: data });
  };

  /**
   * Render
   *
   * @returns {view}
   */
  render() {
    return (
      <>
        <div className="user">
          {this.fields && (
            <EditableTable
              key={MENU_ITEMS.BONUS.POINT_SETTINGS_VIEW.path}
              tableRows={this.state.pointSettings}
              currency={this.props.currency}
              fields={this.fields}
              edit={this.edit}
              save={this.save}
              setNavigationInfo={this.props.setNavigationInfo}
              nextNavigationLink={this.props.nextNavigationLink}
              setTableInfo={this.setTableInfo}
              ref={(ref) => {
                this.editableTable = ref;
              }}
            />
          )}
        </div>
        {this.props.activeModal === MODALS.SAVE_BEFORE_NAVIGATION ? (
          <ConfirmationModal
            modalData={CONFIRM_MODAL_CONTENT.SAVE_CHANGES}
            cancel={this.unsavedNavigation}
            confirmation={this.save}
            cancelBtnText="Cancel"
            confirmBtnText="Save"
            logo
          />
        ) : null}
      </>
    );
  }
}

export default connect(mapToProps, actionsToProps)(withRouterHooks(PointSettings));