226 lines
6.3 KiB
JavaScript
Raw Normal View History

2017-06-18 17:23:58 +02:00
/**
*
* SelectMany
2017-06-18 17:23:58 +02:00
*
*/
import React from 'react';
2017-06-18 17:23:58 +02:00
import Select from 'react-select';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import { cloneDeep, isArray, isNull, isUndefined, get, findIndex, isEmpty } from 'lodash';
2017-06-18 17:23:58 +02:00
// Utils.
2017-06-18 17:23:58 +02:00
import request from 'utils/request';
import templateObject from 'utils/templateObject';
2017-06-18 17:23:58 +02:00
// CSS.
import 'react-select/dist/react-select.css';
// Component.
import SortableList from './SortableList';
// CSS.
import styles from './styles.scss';
class SelectMany extends React.PureComponent {
state = {
isLoading: true,
options: [],
toSkip: 0,
};
2017-06-18 17:23:58 +02:00
2018-04-19 17:19:56 +02:00
componentDidMount() {
this.getOptions('');
}
componentDidUpdate(prevProps, prevState) {
if (isEmpty(prevProps.record) && !isEmpty(this.props.record)) {
const values = (get(this.props.record, this.props.relation.alias) || [])
.map(el => (el.id || el._id));
const options = this.state.options.filter(el => {
return !values.includes(el.value.id || el.value._id);
});
this.state.options = options;
}
2018-04-19 17:19:56 +02:00
if (prevState.toSkip !== this.state.toSkip) {
this.getOptions('');
}
}
2018-04-19 15:45:35 +02:00
getOptions = query => {
const params = {
2018-05-23 10:57:51 +02:00
_limit: 20,
_start: this.state.toSkip,
source: this.props.relation.plugin || 'content-manager',
};
2017-06-18 17:23:58 +02:00
// Set `query` parameter if necessary
if (query) {
2018-05-23 10:57:51 +02:00
delete params._limit;
delete params._skip;
2018-04-19 15:45:35 +02:00
params[`${this.props.relation.displayedAttribute}_contains`] = query;
2017-06-18 17:23:58 +02:00
}
// Request URL
2018-04-19 15:45:35 +02:00
const requestUrl = `/content-manager/explorer/${this.props.relation.model ||
2018-04-23 11:36:21 +02:00
this.props.relation.collection}`;
2017-06-18 17:23:58 +02:00
// Call our request helper (see 'utils/request')
2017-06-19 19:47:38 +02:00
return request(requestUrl, {
2017-06-18 17:23:58 +02:00
method: 'GET',
params,
})
.then(response => {
2018-04-19 15:45:35 +02:00
const options = isArray(response)
? response.map(item => ({
value: item,
2018-04-19 15:45:35 +02:00
label: templateObject({ mainField: this.props.relation.displayedAttribute }, item)
.mainField,
}))
: [
{
value: response,
label: response[this.props.relation.displayedAttribute],
},
];
2017-06-18 17:23:58 +02:00
2018-04-19 17:19:56 +02:00
const newOptions = cloneDeep(this.state.options);
options.map(option => {
// Don't add the values when searching
if (findIndex(newOptions, o => o.value.id === option.value.id) === -1) {
return newOptions.push(option);
}
});
return this.setState({
options: newOptions,
isLoading: false,
});
2017-09-25 15:35:27 +02:00
})
.catch(() => {
2017-12-07 13:26:25 +01:00
strapi.notification.error('content-manager.notification.error.relationship.fetch');
2017-06-18 17:23:58 +02:00
});
2018-04-19 15:45:35 +02:00
};
2017-06-18 17:23:58 +02:00
2018-04-19 15:45:35 +02:00
handleChange = value => {
// Remove new added value from available option;
this.state.options = this.state.options.filter(el =>
!((el.value._id || el.value.id) === (value.value.id || value.value._id))
2018-04-19 15:45:35 +02:00
);
2017-10-21 15:25:00 +02:00
this.props.onAddRelationalItem({
key: this.props.relation.alias,
value: value.value,
});
2018-04-19 15:45:35 +02:00
};
2018-04-19 17:19:56 +02:00
handleBottomScroll = () => {
this.setState(prevState => {
return {
toSkip: prevState.toSkip + 20,
};
});
}
handleRemove = (index) => {
const values = get(this.props.record, this.props.relation.alias);
// Add removed value from available option;
2018-08-09 17:02:15 +02:00
const toAdd = {
value: values[index],
2018-08-09 17:02:15 +02:00
label: templateObject({ mainField: this.props.relation.displayedAttribute }, values[index]).mainField,
};
this.setState(prevState => ({
options: prevState.options.concat([toAdd]),
}));
this.props.onRemoveRelationItem({
key: this.props.relation.alias,
index,
});
}
// Redirect to the edit page
handleClick = (item = {}) => {
this.props.onRedirect({
model: this.props.relation.collection || this.props.relation.model,
id: item.value.id || item.value._id,
source: this.props.relation.plugin,
});
2018-04-19 17:19:56 +02:00
}
2017-06-18 17:23:58 +02:00
render() {
2018-04-19 15:45:35 +02:00
const description = this.props.relation.description ? (
<p>{this.props.relation.description}</p>
) : (
''
);
const value = get(this.props.record, this.props.relation.alias) || [];
2018-07-16 17:26:51 +02:00
2017-08-29 17:32:48 +02:00
/* eslint-disable jsx-a11y/label-has-for */
2017-06-18 17:23:58 +02:00
return (
<div className={`form-group ${styles.selectMany} ${value.length > 4 && styles.selectManyUpdate}`}>
<label htmlFor={this.props.relation.alias}>{this.props.relation.alias} <span>({value.length})</span></label>
2017-06-20 19:10:23 +02:00
{description}
2018-04-19 17:19:56 +02:00
<Select
className={`${styles.select}`}
2017-10-21 15:25:00 +02:00
id={this.props.relation.alias}
2018-04-19 17:19:56 +02:00
isLoading={this.state.isLoading}
onChange={this.handleChange}
2018-04-19 17:19:56 +02:00
onMenuScrollToBottom={this.handleBottomScroll}
options={this.state.options}
placeholder={<FormattedMessage id='content-manager.containers.Edit.addAnItem' />}
/>
<SortableList
items={
2018-04-19 15:45:35 +02:00
isNull(value) || isUndefined(value) || value.size === 0
? null
: value.map(item => {
2018-07-16 17:26:51 +02:00
2018-04-19 15:45:35 +02:00
if (item) {
return {
value: get(item, 'value') || item,
label:
get(item, 'label') ||
templateObject({ mainField: this.props.relation.displayedAttribute }, item)
.mainField ||
2018-07-16 17:26:51 +02:00
item.id,
2018-04-19 15:45:35 +02:00
};
}
})
}
2018-08-09 17:02:15 +02:00
isDraggingSibling={this.props.isDraggingSibling}
2018-08-09 14:59:33 +02:00
keys={this.props.relation.alias}
moveAttr={this.props.moveAttr}
2018-08-09 17:02:15 +02:00
moveAttrEnd={this.props.moveAttrEnd}
onRemove={this.handleRemove}
distance={1}
onClick={this.handleClick}
2017-06-18 17:23:58 +02:00
/>
</div>
);
2017-08-29 17:32:48 +02:00
/* eslint-disable jsx-a11y/label-has-for */
2017-06-18 17:23:58 +02:00
}
}
2018-08-09 14:59:33 +02:00
SelectMany.defaultProps = {
2018-08-09 17:02:15 +02:00
isDraggingSibling: false,
2018-08-09 14:59:33 +02:00
moveAttr: () => {},
2018-08-09 17:02:15 +02:00
moveAttrEnd: () => {},
2018-08-09 14:59:33 +02:00
};
SelectMany.propTypes = {
2018-08-09 17:02:15 +02:00
isDraggingSibling: PropTypes.bool,
2018-08-09 14:59:33 +02:00
moveAttr: PropTypes.func,
2018-08-09 17:02:15 +02:00
moveAttrEnd: PropTypes.func,
onAddRelationalItem: PropTypes.func.isRequired,
onRedirect: PropTypes.func.isRequired,
onRemoveRelationItem: PropTypes.func.isRequired,
2018-04-19 15:45:35 +02:00
record: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]).isRequired,
relation: PropTypes.object.isRequired,
2017-06-18 17:23:58 +02:00
};
export default SelectMany;