src/components/widgets/Table/cells/EditableCell/EditableCell.jsx
import React from 'react';
import cn from 'classnames';
import { compose } from 'recompose';
import { HotKeys } from 'react-hotkeys';
import PropTypes from 'prop-types';
import { isEqual, get, isObject, set } from 'lodash';
import Text from '../../../../snippets/Text/Text';
import withActionsEditableCell from './withActionsEditableCell';
import withCell from '../../withCell';
/**
* Компонент редактируемой ячейки таблицы
* @reactProps {boolean} visible - флаг видимости
* @reactProps {object} control - настройки компонента фильтрации
* @reactProps {boolean} editable - флаг разрешения редактирования
* @reactProps {string} model - значение модели
* @reactProps {boolean} disabled - флаг активности
*/
export class EditableCell extends React.Component {
constructor(props) {
super(props);
this.state = {
model: props.model || {},
editing: false,
prevModel: {},
};
this.onChange = this.onChange.bind(this);
this.toggleEdit = this.toggleEdit.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.callAction = this.callAction.bind(this);
}
componentDidUpdate(prevProps, prevState) {
if (!isEqual(prevProps.model, this.props.model)) {
this.setState({
prevModel: this.state.model,
model: this.props.prevResolveModel,
});
} else if (
!isEqual(prevProps.prevResolveModel, this.props.prevResolveModel) &&
this.props.prevResolveModel.id === this.state.model.id
) {
this.setState({
prevModel: this.state.model,
model: this.props.prevResolveModel,
});
}
if (
!this.state.editing &&
isEqual(prevState.prevModel, prevState.model) &&
!isEqual(this.state.prevModel, this.state.model) &&
!isEqual(this.state.model, this.props.prevResolveModel)
) {
this.callAction(this.state.model);
}
}
onChange(value) {
const newModel = Object.assign({}, this.state.model);
const { editFieldId } = this.props;
set(newModel, editFieldId, value);
this.setState({
model: newModel,
});
}
toggleEdit() {
const { model, prevResolveModel, onSetSelectedId } = this.props;
let newState = {
editing: !this.state.editing,
};
if (!isEqual(get(prevResolveModel, 'id'), get(model, 'id'))) {
onSetSelectedId();
}
if (!newState.editing && !isEqual(this.state.prevModel, this.state.model)) {
this.callAction(this.state.model);
}
newState = {
...newState,
prevModel: this.state.model,
};
this.setState(newState);
}
callAction(model) {
const { callInvoke, action, onResolve, widgetId } = this.props;
const dataProvider = get(action, 'options.payload.dataProvider');
const meta = get(action, 'options.meta');
callInvoke(model, dataProvider, meta);
onResolve(widgetId, model);
}
handleKeyDown() {
this.toggleEdit();
}
stopPropagation(e) {
e.stopPropagation();
}
render() {
const {
visible,
control,
editable,
format,
fieldKey,
editFieldId,
} = this.props;
const { editing, model } = this.state;
const events = { events: 'enter' };
const handlers = { events: this.handleKeyDown };
return (
visible && (
<div
className={cn({ 'n2o-editable-cell': editable })}
onClick={this.stopPropagation}
>
{!editing && (
<div
className="n2o-editable-cell-text"
onClick={editable && this.toggleEdit}
>
<Text text={get(model, fieldKey)} format={format} />
</div>
)}
{editable && editing && (
<HotKeys keyMap={events} handlers={handlers}>
<div className="n2o-editable-cell-control">
{React.createElement(control.component, {
...control,
className: 'n2o-advanced-table-edit-control',
onChange: this.onChange,
onBlur: this.toggleEdit,
autoFocus: true,
value: get(model, editFieldId),
openOnFocus: true,
showButtons: false,
resetOnNotValid: false,
})}
</div>
</HotKeys>
)}
</div>
)
);
}
}
EditableCell.propTypes = {
visible: PropTypes.bool,
control: PropTypes.object,
editable: PropTypes.bool,
value: PropTypes.string,
disabled: PropTypes.bool,
valueFieldId: PropTypes.string,
editFieldId: PropTypes.string,
};
EditableCell.defaultProps = {
visible: true,
disabled: false,
};
export default compose(
withActionsEditableCell,
withCell
)(EditableCell);