design-comuni-plone-theme
Version:
Volto Theme for Italia design guidelines
338 lines (319 loc) • 11.6 kB
JSX
// CUSTOMIZATION:
// - 112-113 reset subscription limit to default when set_limit is not active
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux';
import {
Segment,
Accordion,
Form,
Button,
Grid,
Confirm,
Dimmer,
Loader,
} from 'semantic-ui-react';
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import { Icon } from '@plone/volto/components';
import upSVG from '@plone/volto/icons/up-key.svg';
import downSVG from '@plone/volto/icons/down-key.svg';
import downloadSVG from '@plone/volto/icons/download.svg';
import deleteSVG from '@plone/volto/icons/delete.svg';
import warningSVG from '@plone/volto/icons/warning.svg';
import {
getFormData,
exportCsvFormData,
clearFormData,
setSubblocksIDList,
} from 'volto-form-block/actions';
import { BlockDataForm } from '@plone/volto/components';
import { flattenToAppURL } from '@plone/volto/helpers';
import { getFieldName } from 'volto-form-block/components/utils';
import 'volto-form-block/components/Sidebar.css';
import config from '@plone/volto/registry';
const messages = defineMessages({
exportCsv: {
id: 'form_edit_exportCsv',
defaultMessage: 'Export data',
},
clearData: {
id: 'form_clear_data',
defaultMessage: 'Clear data',
},
formDataCount: {
id: 'form_formDataCount',
defaultMessage: '{formDataCount} item(s) stored',
},
confirmClearData: {
id: 'form_confirmClearData',
defaultMessage: 'Are you sure you want to delete all saved items?',
},
cancel: {
id: 'Cancel',
defaultMessage: 'Cancel',
},
fieldId: {
id: 'fieldId',
defaultMessage: 'Field ID',
},
remove_data_cron_info: {
id: 'remove_data_cron_info',
defaultMessage:
'To automate the removal of records that have exceeded the maximum number of days indicated in configuration, a cron must be set up on the server as indicated in the product documentation.',
},
remove_data_warning: {
id: 'remove_data_warning',
defaultMessage:
'There are {record} record that have exceeded the maximum number of days.',
},
remove_data_button: {
id: 'remove_data_button',
defaultMessage: 'remove expired data',
},
});
const Sidebar = ({
data,
properties,
block,
onChangeBlock,
onChangeSubBlock,
selected = 0,
setSelected,
}) => {
const intl = useIntl();
const dispatch = useDispatch();
const [confirmOpen, setConfirmOpen] = useState(false);
const formData = useSelector((state) => state.formData);
const clearFormDataState = useSelector(
(state) => state.clearFormData?.loaded,
);
useEffect(() => {
if (properties?.['@id'])
dispatch(
getFormData({
path: flattenToAppURL(properties['@id']),
block_id: block,
}),
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [clearFormDataState]);
if (data.send_email === undefined) data.send_email = true;
// reset subscription limit to default when set_limit is not active
if (data.set_limit === false) data.limit = -1;
data.subblocks &&
data.subblocks.forEach((subblock) => {
subblock.field_id = subblock.id;
});
var FormSchema = config.blocks.blocksConfig.form.formSchema;
var FieldSchema = config.blocks.blocksConfig.form.fieldSchema;
// update list of fields ID
useEffect(() => {
if (data.subblocks?.length > 0) {
dispatch(setSubblocksIDList(data.subblocks));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [data]);
return (
<Form>
<Segment.Group raised>
<header className="header pulled">
<h2>
<FormattedMessage id="Form" defaultMessage="Form" />
</h2>
</header>
<Segment>
<BlockDataForm
schema={FormSchema(data)}
onChangeField={(id, value) => {
onChangeBlock(block, {
...data,
[id]: value,
});
}}
formData={data}
/>
{properties?.['@components']?.form_data && (
<Form.Field inline>
<Grid>
<Grid.Row stretched centered style={{ padding: '1rem 0' }}>
<Dimmer active={formData?.loading}>
<Loader size="tiny" />
</Dimmer>
<p>
{intl.formatMessage(messages.formDataCount, {
formDataCount: formData?.result?.items_total ?? 0,
})}
</p>
</Grid.Row>
<Grid.Row
stretched
centered
columns={2}
style={{ marginBottom: '0.5rem' }}
>
<Grid.Column>
<Button
compact
onClick={() =>
dispatch(
exportCsvFormData(
flattenToAppURL(properties['@id']),
`export-${properties.id ?? 'form'}.csv`,
block,
),
)
}
size="tiny"
style={{ display: 'flex', alignItems: 'center' }}
>
<Icon name={downloadSVG} size="1.5rem" />{' '}
{intl.formatMessage(messages.exportCsv)}
</Button>
</Grid.Column>
<Grid.Column>
<Button
compact
onClick={() => setConfirmOpen(true)}
size="tiny"
style={{ display: 'flex', alignItems: 'center' }}
>
<Icon name={deleteSVG} size="1.5rem" />{' '}
{intl.formatMessage(messages.clearData)}
</Button>
<Confirm
open={confirmOpen}
content={intl.formatMessage(messages.confirmClearData)}
cancelButton={intl.formatMessage(messages.cancel)}
onCancel={() => setConfirmOpen(false)}
onConfirm={() => {
dispatch(
clearFormData({
path: flattenToAppURL(properties['@id']),
block_id: block,
}),
);
setConfirmOpen(false);
}}
/>
</Grid.Column>
</Grid.Row>
{data.remove_data_after_days > 0 && (
<Grid.Row>
<div class="ui message info tiny">
{formData.loaded &&
formData.result?.expired_total > 0 && (
<>
<p>
<Icon name={warningSVG} size="18px" />
{intl.formatMessage(
messages.remove_data_warning,
{
record: formData.result.expired_total,
},
)}
</p>
<p>
<Button
onClick={() =>
dispatch(
clearFormData({
path: flattenToAppURL(properties['@id']),
expired: true,
block_id: block,
}),
)
}
size="tiny"
compact
style={{
display: 'flex',
alignItems: 'center',
}}
>
<Icon name={deleteSVG} size="1.5rem" />{' '}
{intl.formatMessage(
messages.remove_data_button,
)}
</Button>
</p>
</>
)}
<p>
{intl.formatMessage(messages.remove_data_cron_info)}
</p>
</div>
</Grid.Row>
)}
</Grid>
</Form.Field>
)}
</Segment>
<Accordion fluid styled className="form">
{data.subblocks &&
data.subblocks.map((subblock, index) => {
return (
<div key={'subblock' + index}>
<Accordion.Title
active={selected === index}
index={index}
onClick={() =>
setSelected(selected === index ? null : index)
}
>
{subblock.label ?? subblock.field_name}
{selected === index ? (
<Icon name={upSVG} size="20px" />
) : (
<Icon name={downSVG} size="20px" />
)}
</Accordion.Title>
<Accordion.Content active={selected === index}>
{/* Field ID info */}
{(subblock.field_type === 'text' ||
subblock.field_type === 'from' ||
subblock.field_type === 'textarea' ||
subblock.field_type === 'date' ||
subblock.field_type === 'single_choice' ||
subblock.field_type === 'multiple_choice' ||
subblock.field_type === 'select' ||
subblock.field_type === 'checkbox' ||
subblock.field_type === 'attachment') && (
<Segment tertiary>
{intl.formatMessage(messages.fieldId)}:{' '}
<strong>
{getFieldName(subblock.label, subblock.field_id)}
</strong>
</Segment>
)}
<BlockDataForm
schema={FieldSchema(subblock)}
onChangeField={(name, value) => {
const update_values = {};
if (subblock.field_type === 'static_text') {
update_values.required = false;
}
onChangeSubBlock(index, {
...subblock,
[name]: value,
...update_values,
});
}}
formData={subblock}
/>
</Accordion.Content>
</div>
);
})}
</Accordion>
</Segment.Group>
</Form>
);
};
Sidebar.propTypes = {
data: PropTypes.objectOf(PropTypes.any),
block: PropTypes.string,
onChangeBlock: PropTypes.func,
selected: PropTypes.any,
setSelected: PropTypes.func,
};
export default Sidebar;