Skip to content

Commit

Permalink
Fix: Escape button in tag edit modal
Browse files Browse the repository at this point in the history
  • Loading branch information
ranbena committed Jan 29, 2019
1 parent 61e7cda commit e7e862c
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 100 deletions.
82 changes: 52 additions & 30 deletions client/app/components/tags-control/TagsControl.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { map, trim } from 'lodash';
import React from 'react';
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { $uibModal } from '@/services/ng';
import TagsEditorModal from './TagsEditorModal';

export default class TagsControl extends React.Component {
static propTypes = {
Expand All @@ -15,27 +15,36 @@ export default class TagsControl extends React.Component {
static defaultProps = {
tags: [],
canEdit: false,
getAvailableTags: () => {},
getAvailableTags: () => Promise.resolve([]),
onEdit: () => {},
className: '',
};

editTags() {
const { getAvailableTags, onEdit } = this.props; // eslint-disable-line react/prop-types
const tags = map(this.props.tags, trim);
constructor(props) {
super(props);

this.state = {
showModal: false,
};

getAvailableTags().then((availableTags) => {
$uibModal
.open({
component: 'tagsEditorModal',
resolve: {
tags: () => tags,
availableTags: () => availableTags,
},
}).result.then((newTags) => {
onEdit(newTags);
});
});
// get available tags
this.props.getAvailableTags()
.then((tags) => {
this.availableTags = tags;
});
}

onTagsChanged = (newTags) => {
this.props.onEdit(newTags);
this.closeEditModal();
}

openEditModal = () => {
this.setState({ showModal: true });
}

closeEditModal = () => {
this.setState({ showModal: false });
}

// eslint-disable-next-line class-methods-use-this
Expand All @@ -55,19 +64,32 @@ export default class TagsControl extends React.Component {
}

renderEditButton() {
if (this.props.canEdit) {
return (this.props.tags.length > 0) ? (
<a className="label label-tag" role="none" onClick={() => this.editTags()}>
<i className="zmdi zmdi-edit" />
</a>
) : (
<a className="label label-tag" role="none" onClick={() => this.editTags()}>
<i className="zmdi zmdi-plus" />
Add tag
</a>
);
if (!this.props.canEdit) {
return null;
}
return null;

const tags = map(this.props.tags, trim);

const buttonLabel = tags.length > 0
? <i className="zmdi zmdi-edit" />
: <Fragment><i className="zmdi zmdi-plus" /> Add tag</Fragment>;

return (
<Fragment>
<a className="label label-tag" role="none" onClick={this.openEditModal}>
{buttonLabel}
</a>
{this.state.showModal
? <TagsEditorModal
tags={tags}
availableTags={this.availableTags}
close={this.onTagsChanged}
dismiss={this.closeEditModal}
/>
: null
}
</Fragment>
);
}

render() {
Expand Down
99 changes: 29 additions & 70 deletions client/app/components/tags-control/TagsEditorModal.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { map, trim, uniq } from 'lodash';
import { map, trim, chain } from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
import { react2angular } from 'react2angular';
import Select from 'antd/lib/select';
import Modal from 'antd/lib/modal';

const { Option } = Select;

class TagsEditorModal extends React.Component {
export default class TagsEditorModal extends React.Component {
static propTypes = {
tags: PropTypes.arrayOf(PropTypes.string),
availableTags: PropTypes.arrayOf(PropTypes.string),
Expand All @@ -23,81 +23,40 @@ class TagsEditorModal extends React.Component {

constructor(props) {
super(props);

this.state = {
result: uniq(map(this.props.tags, trim)),
result: chain(this.props.tags).map(trim).uniq().value(),
};
this.selectRef = React.createRef();
}

componentDidMount() {
// `autoFocus` does not work on Select because its `componentDidMount` is fired before the component
// is actually visible, so it cannot get focus. This hack should be replaced with `autoFocus` prop
// when Angular will finally gone
setTimeout(() => {
if (
this.selectRef.current &&
this.selectRef.current.rcSelect &&
this.selectRef.current.rcSelect.inputRef
) {
this.selectRef.current.rcSelect.inputRef.focus();
}
});
this.selectOptions =
chain(this.props.availableTags)
.map(trim)
.uniq()
.map(tag => <Option key={tag}>{tag}</Option>)
.value();
}

render() {
const {
availableTags,
close,
dismiss,
} = this.props;

const uniqueAvailableTags = uniq(map(availableTags, trim));
const { close, dismiss } = this.props;
const { result } = this.state;

return (
<div>
<div className="modal-header">
<button type="button" className="close" aria-hidden="true" onClick={dismiss}>&times;</button>
<h4 className="modal-title">Add/Edit Tags</h4>
</div>
<div className="modal-body">
<Select
ref={this.selectRef}
mode="tags"
className="w-100"
placeholder="Add some tags..."
defaultValue={this.state.result}
onChange={values => this.setState({ result: map(values, trim) })}
dropdownClassName="ant-dropdown-in-bootstrap-modal"
>
{uniqueAvailableTags.map(tag => (<Option key={tag}>{tag}</Option>))}
</Select>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" onClick={dismiss}>Close</button>
<button type="button" className="btn btn-primary" onClick={() => close({ $value: this.state.result })}>Save</button>
</div>
</div>
<Modal
visible
title="Add/Edit Tags"
onOk={() => close(result)}
onCancel={dismiss}
>
<Select
mode="tags"
className="w-100"
placeholder="Add some tags..."
defaultValue={result}
onChange={values => this.setState({ result: map(values, trim) })}
>
{this.selectOptions}
</Select>
</Modal>
);
}
}

export default function init(ngModule) {
ngModule.component('tagsEditorModal', {
template: `
<tags-editor-modal-impl
tags="$ctrl.resolve.tags"
available-tags="$ctrl.resolve.availableTags"
close="$ctrl.close"
dismiss="$ctrl.dismiss"
></tags-editor-modal-impl>
`,
bindings: {
resolve: '<',
close: '&',
dismiss: '&',
},
});
ngModule.component('tagsEditorModalImpl', react2angular(TagsEditorModal));
}

init.init = true;

0 comments on commit e7e862c

Please sign in to comment.