cspace-ui
Version:
CollectionSpace user interface for browsers
204 lines (176 loc) • 5.53 kB
JSX
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { defineMessages, FormattedMessage } from 'react-intl';
import Immutable from 'immutable';
import { Modal } from 'cspace-layout';
import { getRecordTypeNameByUri } from '../../helpers/configHelpers';
import { canRelate } from '../../helpers/permissionHelpers';
import SearchToSelectModalContainer from '../../containers/search/SearchToSelectModalContainer';
import relateButtonStyles from '../../../styles/cspace-ui/RelateButton.css';
const isSingleSubject = (subjects) => (Array.isArray(subjects) && subjects.length === 1);
const messages = defineMessages({
label: {
id: 'searchToRelateModal.label',
defaultMessage: 'Relate records',
},
accept: {
id: 'searchToRelateModal.accept',
description: 'Label of the accept selection button in the search to relate modal.',
defaultMessage: 'Relate selected',
},
relating: {
id: 'searchToRelateModal.relating',
defaultMessage: 'Relating…',
},
title: {
id: 'searchToRelateModal.title',
defaultMessage: 'Relate {typeName} {query}',
},
errorTitle: {
id: 'searchToRelateModal.errorTitle',
defaultMessage: 'Permission Denied',
},
});
const errorMessages = defineMessages({
locked: {
id: 'searchToRelateModal.error.locked',
defaultMessage: 'Locked records are selected. Relations cannot be made to locked records.',
},
notPermitted: {
id: 'searchToRelateModal.error.notPermitted',
defaultMessage: '{selectedCount, plural, one {{name} record is} other {{name} records are}} selected. You are not permitted to create relations to {collectionName}.',
},
});
const renderRelatingMessage = () => (
<p><FormattedMessage {...messages.relating} /></p>
);
const propTypes = {
config: PropTypes.shape({
recordTypes: PropTypes.object,
}),
error: PropTypes.shape({
code: PropTypes.string,
values: PropTypes.object,
}),
isOpen: PropTypes.bool,
perms: PropTypes.instanceOf(Immutable.Map),
subjects: PropTypes.oneOfType([
PropTypes.arrayOf(
PropTypes.shape({
/* eslint-disable react/no-unused-prop-types */
csid: PropTypes.string,
recordType: PropTypes.string,
/* eslint-enable react/no-unused-prop-types */
}),
),
PropTypes.func,
]),
createRelations: PropTypes.func,
onCancelButtonClick: PropTypes.func,
onCloseButtonClick: PropTypes.func,
onRelationsCreated: PropTypes.func,
};
export default class SearchToRelateModal extends Component {
constructor(props) {
super(props);
this.customizeSearchDescriptor = this.customizeSearchDescriptor.bind(this);
this.handleAccept = this.handleAccept.bind(this);
this.shouldShowCheckbox = this.shouldShowCheckbox.bind(this);
}
handleAccept(selectedItems, searchDescriptor) {
return this.relate(selectedItems, searchDescriptor);
}
customizeSearchDescriptor(searchDescriptor) {
const {
subjects,
} = this.props;
if (isSingleSubject(subjects)) {
return searchDescriptor.setIn(['searchQuery', 'mkRtSbj'], subjects[0].csid);
}
return searchDescriptor;
}
relate(selectedItems, searchDescriptor) {
const {
createRelations,
onRelationsCreated,
} = this.props;
if (createRelations) {
let {
subjects,
} = this.props;
if (typeof subjects === 'function') {
subjects = subjects();
}
if (subjects && subjects.length > 0) {
const objects = selectedItems.valueSeq().map((item) => ({
csid: item.get('csid'),
recordType: searchDescriptor.get('recordType'),
})).toJS();
return createRelations(subjects, objects, 'affects')
.then(() => {
if (onRelationsCreated) {
onRelationsCreated();
}
});
}
}
return undefined;
}
shouldShowCheckbox(item) {
if (item.get('workflowState') === 'locked') {
return false;
}
if (item.get('related') === 'true') {
return false;
}
const {
config,
perms,
subjects,
} = this.props;
if (isSingleSubject(subjects) && item.get('csid') === subjects[0].csid) {
return false;
}
return canRelate(getRecordTypeNameByUri(config, item.get('uri')), perms, config);
}
render() {
const {
error,
subjects,
createRelations,
onRelationsCreated,
...remainingProps
} = this.props;
const {
isOpen,
onCancelButtonClick,
onCloseButtonClick,
} = remainingProps;
if (isOpen && error) {
return (
<Modal
isOpen
showCancelButton={false}
title={<h1><FormattedMessage {...messages.errorTitle} /></h1>}
onAcceptButtonClick={onCancelButtonClick}
onCloseButtonClick={onCloseButtonClick}
>
<FormattedMessage {...errorMessages[error.code]} values={error.values || {}} />
</Modal>
);
}
return (
<SearchToSelectModalContainer
acceptButtonClassName={relateButtonStyles.common}
acceptButtonLabel={<FormattedMessage {...messages.accept} />}
customizeSearchDescriptor={this.customizeSearchDescriptor}
titleMessage={messages.title}
renderAcceptPending={renderRelatingMessage}
shouldShowCheckbox={this.shouldShowCheckbox}
onAccept={this.handleAccept}
{...remainingProps}
/>
);
}
}
SearchToRelateModal.propTypes = propTypes;