components/MenuItems/Settings/EditableSettingsTable.js

import React, { Component } from 'react';

/**
 * @module MI-Settings/EditableSettingsTable
 */
/**
 * @typedef {object} props
 * @property {Array} tableRows
 * @property {Array} fields
 * @property {Array} editPermission
 * @property {Function} save
 * @property {Function} setTableInfo
 * @property {Function} setNavigationInfo set navigation info for unsaved data
 */
export default class EditableSettingsTable extends Component {
  constructor(props) {
    super(props);
    /**
     * @member {object}
     * @property {number|null} editRow
     * @property {Array} tableRows
     */
    this.state = {
      editRow: null,
      tableRows: this.getStartArray(props.tableRows),
      isEdited: false,
    };
  }

  /**
   * update check for modified fields
   *
   * @function
   * @param {object} _
   * @param {object} prevState
   * @returns {void}
   */
  componentDidUpdate(_, prevState) {
    if (prevState.isEdited !== this.state.isEdited) {
      this.props.setNavigationInfo({ hasFieldDataModified: this.state.isEdited });
    }
  }

  /**
   * clear navigation info
   *
   * @returns {void}
   */
  componentWillUnmount() {
    this.props.setNavigationInfo({});
  }

  /**
   * Revert changes to beggining values
   *
   * @function
   * @returns {void}
   */
  setInitalData = () => {
    const rows = this.getStartArray(this.props.tableRows);
    this.setState({
      editRow: null,
      tableRows: rows,
      isEdited: false,
    });
  };

  /**
   * Return data from table
   *
   * @param newData
   * @function
   * @returns {Array}
   */
  getTableData = (newData) => {
    let data = [...newData];
    if (this.state.editRow !== null) {
      data = this.clearChanges();
    }
    return data;
  };

  /**
   * Return beggining values of a table
   *
   * @function
   * @param {Array} tableRows
   * @returns {Array}
   */
  getStartArray = (tableRows) => {
    const newArray = [];
    tableRows.map((itemSettings) => {
      newArray.push({ ...itemSettings });
    });
    return newArray;
  };

  /**
   * Revert changes
   *
   * @function
   * @returns {void}
   */
  clearChanges = () => {
    const data = this.state.tableRows;
    // data[this.state.editRow] = this.state.previousRow;
    this.setState({
      tableRows: data,
      editRow: null,
      isEdited: false,
    });
    return data;
  };

  /**
   * Retrieve table data
   *
   * @param newData
   * @function
   * @returns {Array}
   */
  setTableInfo = (newData) => {
    const data = this.getTableData(newData);
    // eslint-disable-next-line no-param-reassign
    data.map((d) => {
      d.edited = false;
    });
    this.props.setTableInfo(data);
    return data;
  };

  /**
   * Change checkbox value
   *
   * @function
   * @param {number} row
   * @param {number} field
   * @returns {void}
   */
  changeStatusField = (row, field) => {
    const newSettings = JSON.parse(JSON.stringify(this.state.tableRows));
    newSettings[row][field] = (newSettings[row][field] + 1) % 2;
    newSettings[row].edited = true;
    this.setState({
      tableRows: newSettings,
      isEdited: true,
    });
    this.setTableInfo(newSettings);
  };

  /**
   * Call API to save data
   *
   * @function
   * @returns {void}
   */
  save = () => {
    const data = this.setTableInfo(this.state.tableRows);
    this.props.save(data);
    this.setState({
      isEdited: false,
    });
  };

  /**
   * Revert data to initial one
   *
   * @function
   * @returns {void}
   */
  cancel = () => {
    this.setInitalData();
  };

  /**
   * @returns {view}
   */
  render() {
    return (
      <>
        <div className="table-wrapper mt-20">
          <div className="table-responsive">
            <table className="table-style  table-s settings" id="data-table">
              <thead>
                <tr>
                  {this.props.fields.map((field) => (
                    <th key={field.label}>{field.label}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {this.state.tableRows?.map((item, row) => (
                  <tr
                    className={`table-style-row ${this.state.editRow === row ? 'active' : ''} ${
                      item.edited && 'edited'
                    }`}
                    // eslint-disable-next-line react/no-array-index-key
                    key={row}
                  >
                    {this.props.fields.map((field) =>
                      field.icon ? (
                        <td
                          key={field.field}
                          className="table-style-league-icon"
                          style={{ backgroundImage: `url(${field.getValue(item, field.field)})` }}
                        />
                      ) : field.checkbox ? (
                        <td key={field.field}>
                          <label className="toggle-switch">
                            <input
                              type="checkbox"
                              checked={field.getValue(item, field.field)}
                              onChange={() => this.changeStatusField(row, field.field)}
                              disabled={!this.props.editPermission}
                            />
                            <span className="toggle-switch__slider" />
                          </label>
                        </td>
                      ) : (
                        <td key={field.field}>{field.getValue(item, field.field)}</td>
                      )
                    )}
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
        <hr className="line-spacer mt-20" />
        {this.props.editPermission && (
          <div className="d-flex justify-content-end mt-20">
            <button
              id="editableSettingsTable_saveBtn"
              type="button"
              className="btn btn-primary"
              onClick={this.save}
              disabled={!this.state.isEdited}
            >
              Save
            </button>
            <button
              id="editableSettingsTable_cancelBtn"
              type="button"
              className="btn btn-secondary ml-3"
              onClick={this.cancel}
              disabled={!this.state.isEdited}
            >
              Cancel
            </button>
          </div>
        )}
      </>
    );
  }
}