import React, { Component } from 'react';
import SVGComponent from '../../SVG/SVGComponent';
import { SVG_ICONS } from '../../../constants';
import DropdownTable from './DropdownTable';
/**
* @module MI-Bonus/EditableTable
*/
/**
* @typedef {object} props
* @property {boolean} edit
* @property {string} currency
* @property {Array} tableRows
* @property {Array} fields
* @property {Function} save
* @property {Function} setNavigationInfo set navigation info for unsaved data
* @property {Function} setTableInfo set modified table data
*/
export default class EditableTable extends Component {
constructor(props) {
super(props);
/**
* @member {object}
* @property {number|null} editRow
* @property {Array} tableRows
* @property {object} previousRow
*/
this.state = {
editRow: null,
tableRows: this.getStartArray(props.tableRows),
previousRow: null,
hadChanges: false,
};
}
/**
* update check for modified fields
*
* @function
* @param {object} prevProps
* @param {object} prevState
* @returns {void}
*/
componentDidUpdate(prevProps, prevState) {
if (prevState.hadChanges !== this.state.hadChanges) {
this.props.setNavigationInfo({ hasFieldDataModified: this.state.hadChanges });
}
if (prevProps.tableRows !== this.props.tableRows) {
this.setState({
tableRows: this.getStartArray(this.props.tableRows),
});
}
}
/**
* clear navigation info
*
* @returns {void}
*/
componentWillUnmount() {
this.props.setNavigationInfo({});
}
/**
* Revert changes to beggining values
*
* @function
* @returns {void}
*/
setInitalData = () => {
this.setState({
tableRows: this.getStartArray(this.props.tableRows),
editRow: null,
previousRow: null,
hadChanges: false,
});
};
/**
* Return data from table
*
* @param newData
* @function
* @returns {Array}
*/
getTableData = (newData) => {
let data = [...newData];
if (!this.state.editingRow && 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((bonus) => {
newArray.push({ ...bonus });
});
return newArray;
};
/**
* Open Edit mode
*
* @function
* @param {number} editRow
* @returns {void}
*/
openEditMode = (editRow) => {
if (editRow !== null) {
this.clearChanges();
}
this.setState({
editRow,
previousRow: { ...this.state.tableRows[editRow] },
editingRow: true,
});
};
/**
* Close edit mode
*
* @function
* @param {boolean} isEdited
* @param {object} bonus
* @returns {void}
*/
closeEditMode = (isEdited, bonus) => {
if (!isEdited) {
this.clearChanges();
} else {
// eslint-disable-next-line no-param-reassign
bonus.edited = true;
this.setState({
editRow: null,
previousRow: null,
hadChanges: true,
editingRow: false,
});
}
};
/**
* Revert changes
*
* @function
* @param {boolean} hasNewChanges
* @returns {void}
*/
clearChanges = (hasNewChanges) => {
const data = [...this.state.tableRows];
if (!hasNewChanges) {
data[this.state.editRow] = this.state.previousRow;
}
this.setState({
tableRows: data,
editRow: null,
previousRow: null,
editingRow: false,
hadChanges: false,
});
return data;
};
/**
* Change input field
*
* @function
* @param {string} value
* @param {string} field
* @param {boolean} [isNumber]
* @returns {void}
*/
changeField = (value, field, isNumber) => {
const newSettings = JSON.parse(JSON.stringify(this.state.tableRows));
const newValue = isNumber ? parseInt(value.replace(/[,.]/g, '')) || 0 : value;
newSettings[this.state.editRow][field] = newValue;
this.setState({
tableRows: newSettings,
hadChanges: true,
});
this.setTableInfo(newSettings);
};
/**
* 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;
};
/**
* Call API to save data
*
* @function
* @returns {void}
*/
save = () => {
const data = this.setTableInfo(this.state.tableRows);
this.props.save(data);
this.setState({
hadChanges: false,
editRow: null,
previousRow: null,
editingRow: false,
});
};
/**
* Revert data to previous one
*
* @function
* @returns {void}
*/
cancel = () => {
this.setInitalData();
};
/**
* Render
*
* @returns {view}
*/
render() {
const disabled = !this.state.hadChanges || this.state.editRow !== null;
return (
<>
<div className="table-wrapper mt-20">
<div className="table-responsive table-fix-10">
<table className="table-style table-s">
<thead>
<tr>
{this.props.fields.map((field) => (
<th key={field.label}>{field.label}</th>
))}
{this.props.edit && <th>Actions</th>}
</tr>
</thead>
<tbody>
{this.state.tableRows.map((bonus, row) => (
<tr
className={`table-style-row ${this.state.editRow === row && 'edit-mode'} ${
bonus.edited && 'edited'
}`}
// eslint-disable-next-line react/no-array-index-key
key={row}
>
{this.props.fields.map((field, col) => (
// eslint-disable-next-line react/no-array-index-key
<td key={col}>
{field.isEditable ? (
field.dropdown ? (
<DropdownTable bonus={bonus} field={field} changeField={this.changeField} />
) : (
<div className="table-style-row-input">
<input
id={`bonusSettings-${row}-${col}`}
value={field.getValue(bonus, field.field)}
onChange={(e) => {
this.changeField(e.target.value, field.field, field.isNumber);
}}
/>
{field.currency && (
<div className="table-style-row-input-curency">{this.props.currency}</div>
)}
</div>
)
) : null}
<div className={field.isEditable ? 'table-style-row-value' : ''}>
{field.getValue(bonus, field.field)} {field.currency && this.props.currency}
</div>
</td>
))}
{this.props.edit && (
<td>
<div className="table-style-row-btn-wrap">
<SVGComponent
className="icon-xxs cancel-btn"
src={`${SVG_ICONS.utility}#cross`}
onClick={this.closeEditMode.bind(this, false)}
/>
<SVGComponent
className="icon-xxs ml-2 confirm-btn"
src={`${SVG_ICONS.utility}#tick`}
onClick={this.closeEditMode.bind(this, true, bonus)}
/>
</div>
<button
id={`edit-${row}`}
type="button"
className="btn btn-edit"
onClick={this.openEditMode.bind(this, row)}
>
Edit
</button>
</td>
)}
</tr>
))}
</tbody>
</table>
</div>
</div>
<hr className="line-spacer mt-20" />
<div className="d-flex justify-content-end mt-20">
<button
id="bonusSettings_save"
type="button"
className="btn btn-primary"
onClick={this.save}
disabled={disabled}
>
Save
</button>
<button
id="bonusSettins_cancel"
type="button"
className="btn btn-secondary ml-3"
onClick={this.cancel}
disabled={disabled}
>
Cancel
</button>
</div>
</>
);
}
}