@plone/volto
Version:
Volto
283 lines (266 loc) • 7.77 kB
JSX
/**
* Content Type component.
* @module components/manage/Controlpanels/ContentType
*/
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { getParentUrl } from '@plone/volto/helpers/Url/Url';
import { createPortal } from 'react-dom';
import { Button, Header } from 'semantic-ui-react';
import { defineMessages, injectIntl } from 'react-intl';
import { toast } from 'react-toastify';
import last from 'lodash/last';
import nth from 'lodash/nth';
import join from 'lodash/join';
import Error from '@plone/volto/components/theme/Error/Error';
import Icon from '@plone/volto/components/theme/Icon/Icon';
import Toolbar from '@plone/volto/components/manage/Toolbar/Toolbar';
import Toast from '@plone/volto/components/manage/Toast/Toast';
import { Form } from '@plone/volto/components/manage/Form';
import {
getControlpanel,
updateControlpanel,
} from '@plone/volto/actions/controlpanels/controlpanels';
import saveSVG from '@plone/volto/icons/save.svg';
import clearSVG from '@plone/volto/icons/clear.svg';
const messages = defineMessages({
title: {
id: '{id} Content Type',
defaultMessage: '{id} Content Type',
},
changesSaved: {
id: 'Changes saved.',
defaultMessage: 'Changes saved.',
},
back: {
id: 'Back',
defaultMessage: 'Back',
},
save: {
id: 'Save',
defaultMessage: 'Save',
},
cancel: {
id: 'Cancel',
defaultMessage: 'Cancel',
},
info: {
id: 'Info',
defaultMessage: 'Info',
},
});
/**
* ContentType class.
* @class ContentType
* @extends Component
*/
class ContentType extends Component {
/**
* Property types.
* @property {Object} propTypes Property types.
* @static
*/
static propTypes = {
updateControlpanel: PropTypes.func.isRequired,
getControlpanel: PropTypes.func.isRequired,
id: PropTypes.string.isRequired,
parent: PropTypes.string.isRequired,
cpanelRequest: PropTypes.objectOf(PropTypes.any).isRequired,
controlpanel: PropTypes.shape({
'@id': PropTypes.string,
data: PropTypes.object,
schema: PropTypes.object,
title: PropTypes.string,
}),
pathname: PropTypes.string.isRequired,
};
/**
* Default properties.
* @property {Object} defaultProps Default properties.
* @static
*/
static defaultProps = {
controlpanel: null,
};
/**
* Constructor
* @method constructor
* @param {Object} props Component properties
* @constructs ContentType
*/
constructor(props) {
super(props);
this.state = {
visual: false,
error: null,
isClient: false,
};
this.onCancel = this.onCancel.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.form = React.createRef();
}
/**
* Component did mount
* @method componentDidMount
* @returns {undefined}
*/
componentDidMount() {
this.props.getControlpanel(join([this.props.parent, this.props.id], '/'));
this.setState({ isClient: true });
}
/**
* Component will receive props
* @method componentWillReceiveProps
* @param {Object} nextProps Next properties
* @returns {undefined}
*/
UNSAFE_componentWillReceiveProps(nextProps) {
// Control Panel GET
if (
this.props.cpanelRequest.get.loading &&
nextProps.cpanelRequest.get.error
) {
this.setState({
error: nextProps.cpanelRequest.get.error,
});
}
// Control Panel PATCH
if (
this.props.cpanelRequest.update.loading &&
nextProps.cpanelRequest.update.loaded
) {
toast.info(
<Toast
info
title={this.props.intl.formatMessage(messages.info)}
content={this.props.intl.formatMessage(messages.changesSaved)}
/>,
);
}
}
/**
* Submit handler
* @method onSubmit
* @param {object} data Form data.
* @returns {undefined}
*/
onSubmit(data) {
this.props.updateControlpanel(this.props.controlpanel['@id'], data);
}
/**
* Cancel handler
* @method onCancel
* @returns {undefined}
*/
onCancel() {
this.props.history.push(getParentUrl(this.props.pathname));
}
/**
* Render method.
* @method render
* @returns {string} Markup for the component.
*/
render() {
// Error
if (this.state.error) {
return <Error error={this.state.error} />;
}
if (this.props.controlpanel) {
let controlpanel = this.props.controlpanel;
if (controlpanel?.data?.filter_content_types === false) {
controlpanel.data.filter_content_types = { title: 'all', token: 'all' };
}
if (controlpanel?.data?.filter_content_types === true) {
if ((controlpanel?.data?.allowed_content_types || []).length) {
controlpanel.data.filter_content_types = {
title: 'some',
token: 'some',
};
} else {
controlpanel.data.filter_content_types = {
title: 'none',
token: 'none',
};
}
}
return (
<div id="page-controlpanel" className="ui container">
<Header disabled>
{this.props.intl.formatMessage(messages.title, {
id: controlpanel.title,
})}
</Header>
<Form
isEditForm
ref={this.form}
schema={controlpanel.schema}
formData={controlpanel.data}
onSubmit={this.onSubmit}
onCancel={this.onCancel}
pathname={this.props.pathname}
visual={this.state.visual}
hideActions
loading={this.props.cpanelRequest.update.loading}
/>
{this.state.isClient &&
createPortal(
<Toolbar
pathname={this.props.pathname}
hideDefaultViewButtons
inner={
<>
<Button
id="toolbar-save"
className="save"
aria-label={this.props.intl.formatMessage(messages.save)}
onClick={() => this.form.current.onSubmit()}
disabled={this.props.cpanelRequest.update.loading}
loading={this.props.cpanelRequest.update.loading}
>
<Icon
name={saveSVG}
className="circled"
size="30px"
title={this.props.intl.formatMessage(messages.save)}
/>
</Button>
<Button
className="cancel"
aria-label={this.props.intl.formatMessage(
messages.cancel,
)}
onClick={() => this.onCancel()}
>
<Icon
name={clearSVG}
className="circled"
size="30px"
title={this.props.intl.formatMessage(messages.cancel)}
/>
</Button>
</>
}
/>,
document.getElementById('toolbar'),
)}
</div>
);
}
return <div />;
}
}
export default compose(
injectIntl,
connect(
(state, props) => ({
controlpanel: state.controlpanels.controlpanel,
cpanelRequest: state.controlpanels,
pathname: props.location.pathname,
id: last(props.location.pathname.split('/')),
parent: nth(props.location.pathname.split('/'), -2),
}),
{ getControlpanel, updateControlpanel },
),
)(ContentType);