@plone/volto
Version:
Volto
207 lines (197 loc) • 5.29 kB
JSX
import { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { Label, Dropdown, Popup, Icon } from 'semantic-ui-react';
import compact from 'lodash/compact';
import concat from 'lodash/concat';
import fromPairs from 'lodash/fromPairs';
import map from 'lodash/map';
import values from 'lodash/values';
import uniqBy from 'lodash/uniqBy';
import { defineMessages, useIntl } from 'react-intl';
import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
import {
resetSearchContent,
searchContent,
} from '@plone/volto/actions/search/search';
import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
const messages = defineMessages({
no_results_found: {
id: 'No results found.',
defaultMessage: 'No results found.',
},
no_value: {
id: 'No value',
defaultMessage: 'No value',
},
});
const ReferenceWidget = (props) => {
const { id, title, value, multiple, onChange } = props;
const intl = useIntl();
const dispatch = useDispatch();
const search = useSelector((state) => state.search.items);
const [choices, setChoices] = useState(
value
? multiple
? fromPairs(
map(value, (value) => [
value['@id'],
{
key: value['@id'],
text: flattenToAppURL(value['@id']),
value: value['@id'],
label: {
content: value.title,
},
data: value,
},
]),
)
: {
[value['@id']]: {
key: value['@id'],
text: flattenToAppURL(value),
value: value['@id'],
label: {
content: value.title,
},
data: value,
},
novalue: {
key: 'novalue',
text: intl.formatMessage(messages.no_value),
value: 'novalue',
data: null,
},
}
: {},
);
useEffect(() => {
dispatch(resetSearchContent());
}, [dispatch]);
useEffect(() => {
setChoices({
...fromPairs(
map(
uniqBy(
map(compact(concat(value, search)), (item) => ({
...item,
'@id': flattenToAppURL(item['@id']),
})),
'@id',
),
(value) => [
value['@id'],
{
key: value['@id'],
text: flattenToAppURL(value['@id']),
value: value['@id'],
label: {
content: value.title,
},
data: value,
},
],
),
),
novalue: {
key: 'novalue',
text: intl.formatMessage(messages.no_value),
value: 'novalue',
data: null,
},
});
}, [intl, search, value]);
const onSearchChange = (event, data) => {
if (data.searchQuery && data.searchQuery !== '') {
dispatch(
searchContent('', {
Title: `*${data.searchQuery}*`,
}),
);
} else {
dispatch(resetSearchContent());
}
};
const renderLabel = (item, index, defaultProps) => {
return (
<Popup
key={item.value}
content={
<>
<Icon name="home" /> {item.value}
</>
}
trigger={
defaultProps && (
<Label active={defaultProps.active}>
{item.label.content}
<Icon
name="delete"
onClick={(event) => {
defaultProps.onRemove(event, defaultProps);
}}
/>
</Label>
)
}
/>
);
};
return (
<FormFieldWrapper {...props}>
<Dropdown
options={values(choices)}
placeholder={title}
search
selection
fluid
noResultsMessage={intl.formatMessage(messages.no_results_found)}
multiple={multiple}
value={
multiple
? value
? map(value, (item) =>
item && item['@id'] ? flattenToAppURL(item['@id']) : item,
)
: []
: value
? flattenToAppURL(value['@id'])
: ''
}
onChange={(event, data) => {
return onChange(
id,
multiple
? map(data.value, (item) => choices[item].data)
: choices[data.value].data,
);
}}
onSearchChange={onSearchChange}
renderLabel={renderLabel}
/>
</FormFieldWrapper>
);
};
ReferenceWidget.propTypes = {
id: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
description: PropTypes.string,
required: PropTypes.bool,
multiple: PropTypes.bool,
error: PropTypes.arrayOf(PropTypes.string),
value: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.object),
PropTypes.object,
]),
onChange: PropTypes.func.isRequired,
wrapped: PropTypes.bool,
};
ReferenceWidget.defaultProps = {
description: null,
required: false,
error: [],
value: null,
multiple: true,
};
export default ReferenceWidget;