Skip to content

Commit

Permalink
feat: add export/clear buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
nzambello committed Mar 12, 2021
1 parent b27b736 commit 9dc8545
Show file tree
Hide file tree
Showing 12 changed files with 425 additions and 29 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"volto-subblocks"
],
"dependencies": {
"file-saver": "^2.0.5",
"react-google-recaptcha-v3": "^1.8.0",
"volto-subblocks": "collective/volto-subblocks#v1.0.1"
}
Expand Down
48 changes: 48 additions & 0 deletions src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,51 @@ export function submitForm(path = '', block_id, data, attachments) {
},
};
}

/**
* exportCsvFormData action
* @modulee actions/exportCsvFormData
*/
export const EXPORT_CSV_FORMDATA = 'EXPORT_CSV_FORMDATA';

export function exportCsvFormData(path = '') {
return {
type: EXPORT_CSV_FORMDATA,
request: {
op: 'get',
path: path + '/@form-data-export',
},
};
}

/**
* getFormData action
* @modulee actions/getFormData
*/
export const GET_FORM_DATA = 'GET_FORMDATA';

export function getFormData(path = '') {
return {
type: GET_FORM_DATA,
request: {
op: 'get',
path: path + '/@form-data',
},
};
}

/**
* clearFormData action
* @modulee actions/getFormData
*/
export const CLEAR_FORM_DATA = 'CLEAR_FORM_DATA';

export function clearFormData(path = '') {
return {
type: CLEAR_FORM_DATA,
request: {
op: 'get',
path: path + '/@form-data-clear',
},
};
}
7 changes: 3 additions & 4 deletions src/components/Edit.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import React from 'react';
import EditBlock from './EditBlock';

import { Segment, Grid, Form, Button } from 'semantic-ui-react';
import {
withDNDContext,
SubblocksEdit,
SubblocksWrapper,
} from 'volto-subblocks';

import { SidebarPortal } from '@plone/volto/components';
import Sidebar from './Sidebar.jsx';

import EditBlock from 'volto-form-block/components/EditBlock';
import Sidebar from 'volto-form-block/components/Sidebar';

import { defineMessages } from 'react-intl';

Expand Down
3 changes: 2 additions & 1 deletion src/components/EditBlock.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { compose } from 'redux';

import { DNDSubblocks, SubblockEdit, Subblock } from 'volto-subblocks';

import Field from './Field';
import Field from 'volto-form-block/components/Field';
import { getFieldName } from './utils';

/**
Expand Down Expand Up @@ -52,6 +52,7 @@ class EditBlock extends SubblockEdit {
key={this.props.data.index}
isOnEdit={true}
id={id}
field_id={id}
index={this.props.data.index}
onChange={() => {}}
/>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Field.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import EmailWidget from '@plone/volto/components/manage/Widgets/EmailWidget';
import CheckboxWidget from '@plone/volto/components/manage/Widgets/CheckboxWidget';
import { DatetimeWidget } from '@plone/volto/components';

import RadioWidget from './Widget/RadioWidget';
import FileWidget from './Widget/FileWidget';
import RadioWidget from 'volto-form-block/components/Widget/RadioWidget';
import FileWidget from 'volto-form-block/components/Widget/FileWidget';

const messages = defineMessages({
select_a_value: {
Expand Down
15 changes: 8 additions & 7 deletions src/components/Form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React, { useState, useEffect, useReducer } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import PropTypes from 'prop-types';
import { useIntl, defineMessages } from 'react-intl';
import { submitForm } from '../actions';
import { getFieldName } from './utils';
import FormView from './FormView';
import { submitForm } from 'volto-form-block/actions';
import { getFieldName } from 'volto-form-block/components/utils';
import FormView from 'volto-form-block/components/FormView';

const messages = defineMessages({
messageSent: {
Expand Down Expand Up @@ -60,10 +60,10 @@ const Form = ({ data, id, path }) => {

const [formState, setFormState] = useReducer(formStateReducer, initialState);
const [formErrors, setFormErrors] = useState([]);
const submitResults = useSelector((state) => state.sendActionForm);
const submitResults = useSelector((state) => state.submitForm);

const onChangeFormData = (field, value, label) => {
setFormData({ field: field, value: { value: value, label: label } });
const onChangeFormData = (field_id, field, value, label) => {
setFormData({ field, value: { field_id, value, label } });
};

useEffect(() => {
Expand Down Expand Up @@ -98,6 +98,7 @@ const Form = ({ data, id, path }) => {
data.subblocks.forEach((subblock, index) => {
let name = getFieldName(subblock.label);
if (formData[name]?.value) {
formData[name].field_id = subblock.field_id;
const isAttachment = subblock.field_type === 'attachment';

if (isAttachment) {
Expand All @@ -111,7 +112,7 @@ const Form = ({ data, id, path }) => {
path,
id,
Object.keys(formData).map((name) => ({
id: name,
field_id: formData[name].field_id,
label: formData[name].label,
value: formData[name].value,
})),
Expand Down
11 changes: 8 additions & 3 deletions src/components/FormView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
Progress,
Button,
} from 'semantic-ui-react';
import { getFieldName } from './utils';
import Field from './Field';
import { getFieldName } from 'volto-form-block/components/utils';
import Field from 'volto-form-block/components/Field';

const messages = defineMessages({
default_submit_label: {
Expand Down Expand Up @@ -94,7 +94,12 @@ const FormView = ({
{...subblock}
name={name}
onChange={(field, value) =>
onChangeFormData(field, value, subblock.label)
onChangeFormData(
subblock.id,
field,
value,
subblock.label,
)
}
value={formData[name]?.value}
valid={isValidField(name)}
Expand Down
130 changes: 119 additions & 11 deletions src/components/Sidebar.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Segment, Accordion, Form } from 'semantic-ui-react';
import { useSelector, useDispatch } from 'react-redux';
import {
Segment,
Accordion,
Form,
Button,
Grid,
Confirm,
Dimmer,
Loader,
} from 'semantic-ui-react';
import {
defineMessages,
useIntl,
Expand All @@ -18,6 +28,14 @@ import {

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 {
getFormData,
exportCsvFormData,
clearFormData,
} from 'volto-form-block/actions';

const messages = defineMessages({
default_to: {
Expand Down Expand Up @@ -102,18 +120,31 @@ const messages = defineMessages({
defaultMessage:
'Questo indirizzo verrà utilizzato come mittente della mail con i dati del form',
},
save_persistent_data: {
store: {
id: 'form_save_persistent_data',
defaultMessage: 'Salva i dati compilati',
},
send_email: {
send: {
id: 'form_send_email',
defaultMessage: 'Invia email al destinatario',
},
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',
},
});

const Sidebar = ({
data,
properties,
block,
onChangeBlock,
onChangeSubBlock,
Expand All @@ -122,12 +153,28 @@ const Sidebar = ({
openObjectBrowser,
}) => {
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(properties['@id']));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [clearFormDataState]);

if (data.send_email === undefined) data.send_email = true;

data.subblocks &&
data.subblocks.forEach((subblock) => {
subblock.field_id = subblock.id;
});

return (
<Form>
<Segment.Group raised form>
<Segment.Group raised>
<header className="header pulled">
<h2>
<FormattedMessage id="Form" defaultMessage="Form" />
Expand Down Expand Up @@ -186,10 +233,10 @@ const Sidebar = ({
/>

<CheckboxWidget
id="save_persistent_data"
title={intl.formatMessage(messages.save_persistent_data)}
id="store"
title={intl.formatMessage(messages.store)}
required={false}
value={data.save_persistent_data ?? false}
value={data.store ?? false}
onChange={(name, value) => {
onChangeBlock(block, {
...data,
Expand All @@ -198,17 +245,78 @@ const Sidebar = ({
}}
/>
<CheckboxWidget
id="send_email"
title={intl.formatMessage(messages.send_email)}
id="send"
title={intl.formatMessage(messages.send)}
required={false}
value={data.send_email ?? false}
value={data.send ?? false}
onChange={(name, value) => {
onChangeBlock(block, {
...data,
[name]: value,
});
}}
/>

{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(
properties['@id'],
`export-${properties.id ?? 'form'}.csv`,
),
)
}
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}
onCancel={() => setConfirmOpen(false)}
onConfirm={() => {
dispatch(clearFormData(properties['@id']));
setConfirmOpen(false);
}}
/>
</Grid.Column>
</Grid.Row>
</Grid>
</Form.Field>
)}
</Segment>
<Accordion fluid styled className="form">
{data.subblocks &&
Expand Down
2 changes: 1 addition & 1 deletion src/components/View.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { GoogleReCaptchaProvider } from 'react-google-recaptcha-v3';
import Form from './Form';
import Form from 'volto-form-block/components/Form';

/**
* View blocks class.
Expand Down
Loading

0 comments on commit 9dc8545

Please sign in to comment.