cspace-ui
Version:
CollectionSpace user interface for browsers
305 lines (266 loc) • 8.74 kB
JSX
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { defineMessages, FormattedMessage, intlShape } from 'react-intl';
import Immutable from 'immutable';
import get from 'lodash/get';
import { Modal } from 'cspace-layout';
import CancelButton from '../navigation/CancelButton';
import DeleteButton from './DeleteButton';
import styles from '../../../styles/cspace-ui/ConfirmRecordDeleteModal.css';
import {
hasHierarchyRelations,
hasNarrowerHierarchyRelations,
} from '../../helpers/recordDataHelpers';
const messages = defineMessages({
title: {
id: 'confirmRecordDeleteModal.title',
description: 'Title of the modal shown to confirm deletion of a record.',
defaultMessage: 'Delete {recordName}',
},
prompt: {
id: 'confirmRecordDeleteModal.prompt',
description: 'The prompt shown to confirm deletion of a record.',
defaultMessage: 'Delete {title}?',
},
hasRelations: {
id: 'confirmRecordDeleteModal.hasRelations',
description: 'The message shown in the confirm delete modal when the record to be deleted is related to other records.',
defaultMessage: 'This record is related to other records. Deleting this record will cause those relationships to be lost.',
},
hasUses: {
id: 'confirmRecordDeleteModal.hasUses',
description: 'The message shown in the confirm delete modal when the record to be deleted is an authority item that is used by other records.',
defaultMessage: '{title} cannot be deleted because it is used by other records.',
},
hasRoleUses: {
id: 'confirmRecordDeleteModal.hasRoleUses',
description: 'The message shown in the confirm delete modal when the record to be deleted is a role that is used by user accounts.',
defaultMessage: '{title} cannot be deleted because it is associated with user accounts.',
},
hasHierarchy: {
id: 'confirmRecordDeleteModal.hasHierarchy',
description: 'The message shown in the confirm delete modal when the record to be deleted has broader or narrower relations.',
defaultMessage: '{title} cannot be deleted because it belongs to a hierarchy. To delete this record, first remove its broader and narrower records.',
},
hasNarrowerHierarchy: {
id: 'confirmRecordDeleteModal.hasNarrowerHierarchy',
description: 'The message shown in the confirm delete modal when deletion of records with broader relations is allowed, but the record to be deleted has narrower relations.',
defaultMessage: '{title} cannot be deleted because it is a broader record in a hierarchy. To delete this record, first remove its narrower records.',
},
});
const propTypes = {
config: PropTypes.shape({
allowDeleteHierarchyLeaves: PropTypes.bool,
recordTypes: PropTypes.object,
}),
csid: PropTypes.string,
data: PropTypes.instanceOf(Immutable.Map),
isOpen: PropTypes.bool,
isSavePending: PropTypes.bool,
recordType: PropTypes.string,
/* eslint-disable react/no-unused-prop-types */
// These actually are used, but not detected by eslint.
checkForRelations: PropTypes.func,
checkForUses: PropTypes.func,
/* eslint-enable react/no-unused-prop-types */
onCancelButtonClick: PropTypes.func,
onCloseButtonClick: PropTypes.func,
onDeleteButtonClick: PropTypes.func,
};
const contextTypes = {
intl: intlShape,
};
export default class ConfirmRecordDeleteModal extends Component {
constructor(props) {
super(props);
this.renderButtonBar = this.renderButtonBar.bind(this);
this.state = {};
}
componentDidMount() {
const {
isOpen,
} = this.props;
if (isOpen) {
this.init(this.props);
}
}
// eslint-disable-next-line camelcase
UNSAFE_componentWillUpdate(nextProps) {
const {
isOpen,
} = this.props;
const {
isOpen: nextIsOpen,
} = nextProps;
if (!isOpen && nextIsOpen) {
this.init(nextProps);
}
}
canDeleteFromHierarchy() {
const {
config,
csid,
data,
} = this.props;
const { allowDeleteHierarchyLeaves } = config;
// If allowDeleteHierarchyLeaves is true, only disallow deleting records that have narrower
// relations. Otherwise, disallow deleting records that have any (either broader or narrower)
// hierarchy relations.
return (
allowDeleteHierarchyLeaves
? !hasNarrowerHierarchyRelations(csid, data)
: !hasHierarchyRelations(data)
);
}
init(props) {
// On open check if the record has relations.
const {
config,
recordType,
checkForRelations,
checkForUses,
checkForRoleUses,
} = props;
const serviceType = get(config, ['recordTypes', recordType, 'serviceConfig', 'serviceType']);
if ((serviceType === 'procedure' || serviceType === 'object') && checkForRelations) {
this.setState({
hasRelations: undefined,
hasUses: false,
});
checkForRelations('affects')
.then((hasRelations) => {
this.setState({
hasRelations,
});
});
} else if (serviceType === 'authority' && checkForUses) {
this.setState({
hasRelations: false,
hasUses: undefined,
});
checkForUses()
.then((hasUses) => {
this.setState({
hasUses,
});
});
} else if (recordType === 'authrole' && checkForRoleUses) {
this.setState({
hasRelations: false,
hasUses: undefined,
});
checkForRoleUses()
.then((hasUses) => {
this.setState({
hasUses,
});
});
} else {
this.setState({
hasRelations: false,
hasUses: false,
});
}
}
renderButtonBar() {
const {
csid,
isSavePending,
onCancelButtonClick,
onDeleteButtonClick,
} = this.props;
const {
hasRelations,
hasUses,
} = this.state;
let deleteButton;
if (!hasUses && this.canDeleteFromHierarchy()) {
deleteButton = (
<DeleteButton
csid={csid}
// Disable the delete button while the check for relations is pending.
disabled={typeof hasRelations === 'undefined'}
// Assume the record is deletable if this modal is being shown.
isDeletable
isSavePending={isSavePending}
onClick={onDeleteButtonClick}
/>
);
}
return (
<div>
<CancelButton
disabled={isSavePending}
onClick={onCancelButtonClick}
/>
{deleteButton}
</div>
);
}
render() {
const {
config,
data,
isOpen,
recordType,
onCloseButtonClick,
} = this.props;
if (!isOpen || !data) {
return null;
}
const {
intl,
} = this.context;
const {
hasRelations,
hasUses,
} = this.state;
const { allowDeleteHierarchyLeaves, recordTypes } = config;
const recordTypeConfig = recordTypes[recordType];
const recordName = intl.formatMessage(recordTypeConfig.messages.record.name);
const title = recordTypeConfig.title(data, { config, intl });
let prompt;
let hasRelationsMessage;
let hasHierarchyMessage;
let hasUsesMessage;
if (typeof hasRelations !== 'undefined' && typeof hasUses !== 'undefined') {
if (!this.canDeleteFromHierarchy()) {
hasHierarchyMessage = allowDeleteHierarchyLeaves
? <FormattedMessage {...messages.hasNarrowerHierarchy} values={{ title }} />
: <FormattedMessage {...messages.hasHierarchy} values={{ title }} />;
} else if (hasUses) {
hasUsesMessage = (recordType === 'authrole')
? <FormattedMessage {...messages.hasRoleUses} values={{ title }} />
: <FormattedMessage {...messages.hasUses} values={{ title }} />;
} else {
prompt = <FormattedMessage {...messages.prompt} values={{ title }} />;
hasRelationsMessage = hasRelations
? (
<div>
<br />
<FormattedMessage {...messages.hasRelations} />
</div>
)
: null;
}
}
return (
<Modal
className={styles.common}
isOpen={isOpen}
title={<h1><FormattedMessage {...messages.title} values={{ recordName }} /></h1>}
closeButtonClassName="material-icons"
closeButtonLabel="close"
renderButtonBar={this.renderButtonBar}
onCloseButtonClick={onCloseButtonClick}
>
{prompt}
{hasRelationsMessage}
{hasHierarchyMessage}
{hasUsesMessage}
</Modal>
);
}
}
ConfirmRecordDeleteModal.propTypes = propTypes;
ConfirmRecordDeleteModal.contextTypes = contextTypes;