design-comuni-plone-theme 11.21.1 → 11.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +23 -0
  3. package/RELEASE.md +18 -0
  4. package/locales/de/LC_MESSAGES/volto.po +40 -5
  5. package/locales/en/LC_MESSAGES/volto.po +40 -5
  6. package/locales/es/LC_MESSAGES/volto.po +40 -5
  7. package/locales/fr/LC_MESSAGES/volto.po +40 -5
  8. package/locales/it/LC_MESSAGES/volto.po +40 -5
  9. package/locales/volto.pot +41 -6
  10. package/package.json +1 -1
  11. package/publiccode.yml +2 -2
  12. package/src/components/ItaliaTheme/Blocks/EventSearch/DefaultFilters.js +1 -11
  13. package/src/components/ItaliaTheme/CustomerSatisfaction/FeedbackForm.jsx +3 -18
  14. package/src/components/ItaliaTheme/View/PersonaView/PersonaDocumenti.jsx +50 -0
  15. package/src/components/ItaliaTheme/View/UOView/UOMetadati.jsx +12 -0
  16. package/src/components/ItaliaTheme/View/UOView/UOView.jsx +3 -0
  17. package/src/components/ItaliaTheme/View/index.js +1 -0
  18. package/src/config/italiaConfig.js +1 -0
  19. package/src/customizations/volto/actions/vocabularies/vocabularies.js +2 -2
  20. package/src/customizations/volto/components/manage/Blocks/Search/SearchBlockView.jsx +35 -9
  21. package/src/customizations/volto/components/manage/Blocks/Search/components/SearchDetails.jsx +2 -3
  22. package/src/customizations/volto/components/manage/Blocks/Search/hocs/withSearch.jsx +6 -4
  23. package/src/customizations/volto/components/theme/Footer/Footer.jsx +7 -13
  24. package/src/customizations/volto-form-block/components/FormResult.jsx +39 -9
  25. package/src/customizations/volto-form-block/components/Sidebar.jsx +325 -0
  26. package/src/customizations/volto-form-block/components/View.jsx +390 -0
  27. package/src/customizations/volto-form-block/fieldSchema.js +174 -0
  28. package/src/customizations/volto-form-block/formSchema.js +237 -0
  29. package/src/overrideTranslations.jsx +26 -0
@@ -0,0 +1,325 @@
1
+ // CUSTOMIZATION:
2
+ // - 112-113 reset subscription limit to default when set_limit is not active
3
+
4
+ import React, { useState, useEffect } from 'react';
5
+ import PropTypes from 'prop-types';
6
+ import { useSelector, useDispatch } from 'react-redux';
7
+ import {
8
+ Segment,
9
+ Accordion,
10
+ Form,
11
+ Button,
12
+ Grid,
13
+ Confirm,
14
+ Dimmer,
15
+ Loader,
16
+ } from 'semantic-ui-react';
17
+ import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
18
+
19
+ import { Icon } from '@plone/volto/components';
20
+
21
+ import upSVG from '@plone/volto/icons/up-key.svg';
22
+ import downSVG from '@plone/volto/icons/down-key.svg';
23
+ import downloadSVG from '@plone/volto/icons/download.svg';
24
+ import deleteSVG from '@plone/volto/icons/delete.svg';
25
+
26
+ import warningSVG from '@plone/volto/icons/warning.svg';
27
+
28
+ import {
29
+ getFormData,
30
+ exportCsvFormData,
31
+ clearFormData,
32
+ } from 'volto-form-block/actions';
33
+
34
+ import { BlockDataForm } from '@plone/volto/components';
35
+ import { flattenToAppURL } from '@plone/volto/helpers';
36
+ import { getFieldName } from 'volto-form-block/components/utils';
37
+
38
+ import 'volto-form-block/components/Sidebar.css';
39
+ import config from '@plone/volto/registry';
40
+
41
+ const messages = defineMessages({
42
+ exportCsv: {
43
+ id: 'form_edit_exportCsv',
44
+ defaultMessage: 'Export data',
45
+ },
46
+ clearData: {
47
+ id: 'form_clear_data',
48
+ defaultMessage: 'Clear data',
49
+ },
50
+ formDataCount: {
51
+ id: 'form_formDataCount',
52
+ defaultMessage: '{formDataCount} item(s) stored',
53
+ },
54
+ confirmClearData: {
55
+ id: 'form_confirmClearData',
56
+ defaultMessage: 'Are you sure you want to delete all saved items?',
57
+ },
58
+ cancel: {
59
+ id: 'Cancel',
60
+ defaultMessage: 'Cancel',
61
+ },
62
+ fieldId: {
63
+ id: 'fieldId',
64
+ defaultMessage: 'Field ID',
65
+ },
66
+ remove_data_cron_info: {
67
+ id: 'remove_data_cron_info',
68
+ defaultMessage:
69
+ '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.',
70
+ },
71
+ remove_data_warning: {
72
+ id: 'remove_data_warning',
73
+ defaultMessage:
74
+ 'There are {record} record that have exceeded the maximum number of days.',
75
+ },
76
+ remove_data_button: {
77
+ id: 'remove_data_button',
78
+ defaultMessage: 'remove expired data',
79
+ },
80
+ });
81
+
82
+ const Sidebar = ({
83
+ data,
84
+ properties,
85
+ block,
86
+ onChangeBlock,
87
+ onChangeSubBlock,
88
+ selected = 0,
89
+ setSelected,
90
+ }) => {
91
+ const intl = useIntl();
92
+ const dispatch = useDispatch();
93
+ const [confirmOpen, setConfirmOpen] = useState(false);
94
+
95
+ const formData = useSelector((state) => state.formData);
96
+ const clearFormDataState = useSelector(
97
+ (state) => state.clearFormData?.loaded,
98
+ );
99
+ useEffect(() => {
100
+ if (properties?.['@id'])
101
+ dispatch(
102
+ getFormData({
103
+ path: flattenToAppURL(properties['@id']),
104
+ block_id: block,
105
+ }),
106
+ );
107
+ // eslint-disable-next-line react-hooks/exhaustive-deps
108
+ }, [clearFormDataState]);
109
+
110
+ if (data.send_email === undefined) data.send_email = true;
111
+
112
+ // reset subscription limit to default when set_limit is not active
113
+ if (data.set_limit === false) data.limit = -1;
114
+
115
+ data.subblocks &&
116
+ data.subblocks.forEach((subblock) => {
117
+ subblock.field_id = subblock.id;
118
+ });
119
+ var FormSchema = config.blocks.blocksConfig.form.formSchema;
120
+ var FieldSchema = config.blocks.blocksConfig.form.fieldSchema;
121
+
122
+ return (
123
+ <Form>
124
+ <Segment.Group raised>
125
+ <header className="header pulled">
126
+ <h2>
127
+ <FormattedMessage id="Form" defaultMessage="Form" />
128
+ </h2>
129
+ </header>
130
+ <Segment>
131
+ <BlockDataForm
132
+ schema={FormSchema(data)}
133
+ onChangeField={(id, value) => {
134
+ onChangeBlock(block, {
135
+ ...data,
136
+ [id]: value,
137
+ });
138
+ }}
139
+ formData={data}
140
+ />
141
+ {properties?.['@components']?.form_data && (
142
+ <Form.Field inline>
143
+ <Grid>
144
+ <Grid.Row stretched centered style={{ padding: '1rem 0' }}>
145
+ <Dimmer active={formData?.loading}>
146
+ <Loader size="tiny" />
147
+ </Dimmer>
148
+ <p>
149
+ {intl.formatMessage(messages.formDataCount, {
150
+ formDataCount: formData?.result?.items_total ?? 0,
151
+ })}
152
+ </p>
153
+ </Grid.Row>
154
+ <Grid.Row
155
+ stretched
156
+ centered
157
+ columns={2}
158
+ style={{ marginBottom: '0.5rem' }}
159
+ >
160
+ <Grid.Column>
161
+ <Button
162
+ compact
163
+ onClick={() =>
164
+ dispatch(
165
+ exportCsvFormData(
166
+ flattenToAppURL(properties['@id']),
167
+ `export-${properties.id ?? 'form'}.csv`,
168
+ block,
169
+ ),
170
+ )
171
+ }
172
+ size="tiny"
173
+ style={{ display: 'flex', alignItems: 'center' }}
174
+ >
175
+ <Icon name={downloadSVG} size="1.5rem" />{' '}
176
+ {intl.formatMessage(messages.exportCsv)}
177
+ </Button>
178
+ </Grid.Column>
179
+ <Grid.Column>
180
+ <Button
181
+ compact
182
+ onClick={() => setConfirmOpen(true)}
183
+ size="tiny"
184
+ style={{ display: 'flex', alignItems: 'center' }}
185
+ >
186
+ <Icon name={deleteSVG} size="1.5rem" />{' '}
187
+ {intl.formatMessage(messages.clearData)}
188
+ </Button>
189
+ <Confirm
190
+ open={confirmOpen}
191
+ content={intl.formatMessage(messages.confirmClearData)}
192
+ cancelButton={intl.formatMessage(messages.cancel)}
193
+ onCancel={() => setConfirmOpen(false)}
194
+ onConfirm={() => {
195
+ dispatch(
196
+ clearFormData({
197
+ path: flattenToAppURL(properties['@id']),
198
+ block_id: block,
199
+ }),
200
+ );
201
+ setConfirmOpen(false);
202
+ }}
203
+ />
204
+ </Grid.Column>
205
+ </Grid.Row>
206
+ {data.remove_data_after_days > 0 && (
207
+ <Grid.Row>
208
+ <div class="ui message info tiny">
209
+ {formData.loaded &&
210
+ formData.result?.expired_total > 0 && (
211
+ <>
212
+ <p>
213
+ <Icon name={warningSVG} size="18px" />
214
+ {intl.formatMessage(
215
+ messages.remove_data_warning,
216
+ {
217
+ record: formData.result.expired_total,
218
+ },
219
+ )}
220
+ </p>
221
+ <p>
222
+ <Button
223
+ onClick={() =>
224
+ dispatch(
225
+ clearFormData({
226
+ path: flattenToAppURL(properties['@id']),
227
+ expired: true,
228
+ block_id: block,
229
+ }),
230
+ )
231
+ }
232
+ size="tiny"
233
+ compact
234
+ style={{
235
+ display: 'flex',
236
+ alignItems: 'center',
237
+ }}
238
+ >
239
+ <Icon name={deleteSVG} size="1.5rem" />{' '}
240
+ {intl.formatMessage(
241
+ messages.remove_data_button,
242
+ )}
243
+ </Button>
244
+ </p>
245
+ </>
246
+ )}
247
+ <p>
248
+ {intl.formatMessage(messages.remove_data_cron_info)}
249
+ </p>
250
+ </div>
251
+ </Grid.Row>
252
+ )}
253
+ </Grid>
254
+ </Form.Field>
255
+ )}
256
+ </Segment>
257
+ <Accordion fluid styled className="form">
258
+ {data.subblocks &&
259
+ data.subblocks.map((subblock, index) => {
260
+ return (
261
+ <div key={'subblock' + index}>
262
+ <Accordion.Title
263
+ active={selected === index}
264
+ index={index}
265
+ onClick={() =>
266
+ setSelected(selected === index ? null : index)
267
+ }
268
+ >
269
+ {subblock.label ?? subblock.field_name}
270
+ {selected === index ? (
271
+ <Icon name={upSVG} size="20px" />
272
+ ) : (
273
+ <Icon name={downSVG} size="20px" />
274
+ )}
275
+ </Accordion.Title>
276
+ <Accordion.Content active={selected === index}>
277
+ {/* Field ID info */}
278
+ {(subblock.field_type === 'text' ||
279
+ subblock.field_type === 'from' ||
280
+ subblock.field_type === 'textarea' ||
281
+ subblock.field_type === 'date' ||
282
+ subblock.field_type === 'single_choice' ||
283
+ subblock.field_type === 'multiple_choice' ||
284
+ subblock.field_type === 'select' ||
285
+ subblock.field_type === 'checkbox' ||
286
+ subblock.field_type === 'attachment') && (
287
+ <Segment tertiary>
288
+ {intl.formatMessage(messages.fieldId)}:{' '}
289
+ <strong>
290
+ {getFieldName(subblock.label, subblock.field_id)}
291
+ </strong>
292
+ </Segment>
293
+ )}
294
+ <BlockDataForm
295
+ schema={FieldSchema(subblock)}
296
+ onChangeField={(name, value) => {
297
+ var update_values = {};
298
+
299
+ onChangeSubBlock(index, {
300
+ ...subblock,
301
+ [name]: value,
302
+ ...update_values,
303
+ });
304
+ }}
305
+ formData={subblock}
306
+ />
307
+ </Accordion.Content>
308
+ </div>
309
+ );
310
+ })}
311
+ </Accordion>
312
+ </Segment.Group>
313
+ </Form>
314
+ );
315
+ };
316
+
317
+ Sidebar.propTypes = {
318
+ data: PropTypes.objectOf(PropTypes.any),
319
+ block: PropTypes.string,
320
+ onChangeBlock: PropTypes.func,
321
+ selected: PropTypes.any,
322
+ setSelected: PropTypes.func,
323
+ };
324
+
325
+ export default Sidebar;
@@ -0,0 +1,390 @@
1
+ // CUSTOMIZATION:
2
+ // - added warning state to form
3
+
4
+ import React, { useState, useEffect, useReducer, useRef } from 'react';
5
+ import { useSelector, useDispatch } from 'react-redux';
6
+ import PropTypes from 'prop-types';
7
+ import { useIntl, defineMessages } from 'react-intl';
8
+ import { submitForm } from 'volto-form-block/actions';
9
+ import { getFieldName } from 'volto-form-block/components/utils';
10
+ import FormView from 'volto-form-block/components/FormView';
11
+ import { formatDate } from '@plone/volto/helpers/Utils/Date';
12
+ import config from '@plone/volto/registry';
13
+ import { Captcha } from 'volto-form-block/components/Widget';
14
+ import { isValidEmail } from 'volto-form-block/helpers/validators';
15
+ import ValidateConfigForm from 'volto-form-block/components/ValidateConfigForm';
16
+ import { OTP_FIELDNAME_EXTENDER } from 'volto-form-block/components/Widget';
17
+
18
+ const messages = defineMessages({
19
+ formSubmitted: {
20
+ id: 'formSubmitted',
21
+ defaultMessage: 'Form successfully submitted',
22
+ },
23
+ defaultInvalidFieldMessage: {
24
+ id: 'formblock_defaultInvalidFieldMessage',
25
+ defaultMessage: 'Invalid field value',
26
+ },
27
+ requiredFieldMessage: {
28
+ id: 'formblock_requiredFieldMessage',
29
+ defaultMessage: 'Fill-in this field',
30
+ },
31
+ invalidEmailMessage: {
32
+ id: 'formblock_invalidEmailMessage',
33
+ defaultMessage: 'The email is incorrect',
34
+ },
35
+ insertOtp: {
36
+ id: 'formblock_insertOtp_error',
37
+ defaultMessage: 'Please, insert the OTP code recived via email.',
38
+ },
39
+ });
40
+
41
+ const initialState = {
42
+ loading: false,
43
+ error: null,
44
+ result: null,
45
+ warning: null,
46
+ };
47
+
48
+ const FORM_STATES = {
49
+ normal: 'normal',
50
+ loading: 'loading',
51
+ error: 'error',
52
+ success: 'success',
53
+ warning: 'warning',
54
+ };
55
+
56
+ const formStateReducer = (state, action) => {
57
+ switch (action.type) {
58
+ case FORM_STATES.normal:
59
+ return initialState;
60
+
61
+ case FORM_STATES.loading:
62
+ return { loading: true, error: null, result: null, warning: null };
63
+
64
+ case FORM_STATES.error:
65
+ return {
66
+ loading: false,
67
+ error: action.error,
68
+ result: null,
69
+ warning: null,
70
+ };
71
+
72
+ case FORM_STATES.warning:
73
+ return {
74
+ loading: false,
75
+ error: null,
76
+ result: action.result,
77
+ warning: true,
78
+ };
79
+
80
+ case FORM_STATES.success:
81
+ return {
82
+ loading: false,
83
+ error: null,
84
+ result: action.result,
85
+ warning: null,
86
+ };
87
+
88
+ default:
89
+ return initialState;
90
+ }
91
+ };
92
+
93
+ const getInitialData = (data) => {
94
+ const { static_fields = [], subblocks = [] } = data;
95
+
96
+ return {
97
+ ...subblocks.reduce(
98
+ (acc, field) =>
99
+ field.field_type === 'hidden'
100
+ ? {
101
+ ...acc,
102
+ [getFieldName(field.label, field.id)]: {
103
+ ...field,
104
+ ...(data[field.id] && { custom_field_id: data[field.id] }),
105
+ },
106
+ }
107
+ : acc,
108
+ {},
109
+ ),
110
+ ...static_fields.reduce(
111
+ (acc, field) => ({
112
+ ...acc,
113
+ [getFieldName(field.label, field.id)]: field,
114
+ }),
115
+ {},
116
+ ),
117
+ };
118
+ };
119
+
120
+ /**
121
+ * Form view
122
+ * @class View
123
+ */
124
+ const View = ({ data, id, path }) => {
125
+ const intl = useIntl();
126
+ const dispatch = useDispatch();
127
+
128
+ const [formData, setFormData] = useReducer((state, action) => {
129
+ if (action.reset) {
130
+ return getInitialData(data);
131
+ }
132
+
133
+ return {
134
+ ...state,
135
+ [action.field]: action.value,
136
+ };
137
+ }, getInitialData(data));
138
+
139
+ const [formState, setFormState] = useReducer(formStateReducer, initialState);
140
+ const [formErrors, setFormErrors] = useState([]);
141
+
142
+ const submitResults = useSelector(
143
+ (state) => state.submitForm?.subrequests?.[id],
144
+ );
145
+ const captchaToken = useRef();
146
+
147
+ const onChangeFormData = (field_id, field, value, extras) => {
148
+ setFormData({ field, value: { field_id, value, ...extras } });
149
+ };
150
+
151
+ useEffect(() => {
152
+ if (formErrors.length > 0) {
153
+ isValidForm();
154
+ }
155
+ // eslint-disable-next-line react-hooks/exhaustive-deps
156
+ }, [formData]);
157
+
158
+ const isValidForm = () => {
159
+ const v = [];
160
+ data.subblocks.forEach((subblock, index) => {
161
+ const name = getFieldName(subblock.label, subblock.id);
162
+ const fieldType = subblock.field_type;
163
+ const isBCC = subblock.use_as_bcc;
164
+ const additionalField =
165
+ config.blocks.blocksConfig.form.additionalFields?.filter(
166
+ (f) => f.id === fieldType && f.isValid !== undefined,
167
+ )?.[0] ?? null;
168
+
169
+ if (
170
+ subblock.required &&
171
+ additionalField &&
172
+ !additionalField?.isValid(formData, name)
173
+ ) {
174
+ const validation = additionalField?.isValid(formData, name);
175
+ if (typeof validation === 'boolean') {
176
+ //for retro-compatibility with previous formErrors structure
177
+ v.push({
178
+ field: name,
179
+ message: intl.formatMessage(messages.defaultInvalidFieldMessage),
180
+ });
181
+ } else if (typeof validation === 'object') {
182
+ v.push(validation);
183
+ }
184
+ } else if (
185
+ subblock.required &&
186
+ fieldType === 'checkbox' &&
187
+ !formData[name]?.value
188
+ ) {
189
+ v.push({
190
+ field: name,
191
+ message: intl.formatMessage(messages.requiredFieldMessage),
192
+ });
193
+ } else if (
194
+ subblock.required &&
195
+ (!formData[name] ||
196
+ formData[name]?.value?.length === 0 ||
197
+ JSON.stringify(formData[name]?.value ?? {}) === '{}')
198
+ ) {
199
+ v.push({
200
+ field: name,
201
+ message: intl.formatMessage(messages.requiredFieldMessage),
202
+ });
203
+ } else if (
204
+ (fieldType === 'from' || fieldType === 'email') &&
205
+ formData[name]?.value
206
+ ) {
207
+ if (!isValidEmail(formData[name].value)) {
208
+ v.push({
209
+ field: name,
210
+ message: intl.formatMessage(messages.invalidEmailMessage),
211
+ });
212
+ } else if (isBCC && !formData[name].otp) {
213
+ v.push({
214
+ field: name + OTP_FIELDNAME_EXTENDER,
215
+ message: intl.formatMessage(messages.insertOtp),
216
+ });
217
+ }
218
+ }
219
+ });
220
+
221
+ if (data.captcha && !captchaToken.current) {
222
+ v.push({
223
+ field: 'captcha',
224
+ message: intl.formatMessage(messages.requiredFieldMessage),
225
+ });
226
+ }
227
+
228
+ setFormErrors(v);
229
+ return v.length === 0;
230
+ };
231
+
232
+ const submit = (e) => {
233
+ e.preventDefault();
234
+ captcha
235
+ .verify()
236
+ .then(() => {
237
+ if (isValidForm()) {
238
+ let attachments = {};
239
+ let captcha = {
240
+ provider: data.captcha,
241
+ token: captchaToken.current,
242
+ };
243
+ if (data.captcha === 'honeypot') {
244
+ captcha.value = formData[data.captcha_props.id]?.value ?? '';
245
+ }
246
+
247
+ let formattedFormData = { ...formData };
248
+ data.subblocks.forEach((subblock) => {
249
+ let name = getFieldName(subblock.label, subblock.id);
250
+ if (formattedFormData[name]?.value) {
251
+ formattedFormData[name].field_id = subblock.field_id;
252
+ const isAttachment =
253
+ config.blocks.blocksConfig.form.attachment_fields.includes(
254
+ subblock.field_type,
255
+ );
256
+ const isDate = subblock.field_type === 'date';
257
+
258
+ if (isAttachment) {
259
+ attachments[name] = formattedFormData[name].value;
260
+ delete formattedFormData[name];
261
+ }
262
+
263
+ if (isDate) {
264
+ formattedFormData[name].value = formatDate({
265
+ date: formattedFormData[name].value,
266
+ format: 'DD-MM-YYYY',
267
+ locale: intl.locale,
268
+ });
269
+ }
270
+ }
271
+ });
272
+ dispatch(
273
+ submitForm(
274
+ path,
275
+ id,
276
+ Object.keys(formattedFormData).map((name) => ({
277
+ ...formattedFormData[name],
278
+ })),
279
+ attachments,
280
+ captcha,
281
+ ),
282
+ );
283
+ setFormState({ type: FORM_STATES.loading });
284
+ } else {
285
+ setFormState({ type: FORM_STATES.error });
286
+ }
287
+ })
288
+ .catch(() => {
289
+ setFormState({ type: FORM_STATES.error });
290
+ });
291
+ };
292
+
293
+ const resetFormState = () => {
294
+ setFormData({ reset: true });
295
+ setFormState({ type: FORM_STATES.normal });
296
+ };
297
+
298
+ const resetFormOnError = () => {
299
+ setFormState({ type: FORM_STATES.normal });
300
+ };
301
+
302
+ const getErrorMessage = (field) => {
303
+ const e = formErrors?.filter((e) => e.field === field);
304
+ return e.length > 0 ? e[0].message : null;
305
+ };
306
+
307
+ const captcha = new Captcha({
308
+ captchaToken,
309
+ captcha: data.captcha,
310
+ captcha_props: data.captcha_props,
311
+ errorMessage: getErrorMessage('captcha'),
312
+ onChangeFormData,
313
+ });
314
+
315
+ const formid = `form-${id}`;
316
+
317
+ useEffect(() => {
318
+ if (submitResults?.loaded) {
319
+ if (submitResults?.result?.data?.waiting_list) {
320
+ setFormState({
321
+ type: FORM_STATES.warning,
322
+ result: {
323
+ ...submitResults.result,
324
+ },
325
+ });
326
+ } else {
327
+ setFormState({
328
+ type: FORM_STATES.success,
329
+ result: {
330
+ message: intl.formatMessage(messages.formSubmitted),
331
+ ...submitResults.result,
332
+ },
333
+ });
334
+ }
335
+ captcha.reset();
336
+ const formItem = document.getElementById(formid);
337
+ if (formItem !== null) {
338
+ const formItemPosition = formItem.getBoundingClientRect();
339
+ formItemPosition !== null &&
340
+ window.scrollTo({
341
+ top: formItemPosition.x,
342
+ left: formItemPosition.y,
343
+ behavior: 'smooth',
344
+ });
345
+ }
346
+ } else if (submitResults?.error) {
347
+ let errorDescription = `${
348
+ JSON.parse(submitResults.error.response?.text ?? '{}')?.message
349
+ }`;
350
+
351
+ setFormState({ type: FORM_STATES.error, error: errorDescription });
352
+ }
353
+ // eslint-disable-next-line react-hooks/exhaustive-deps
354
+ }, [submitResults]);
355
+
356
+ useEffect(() => {
357
+ resetFormState();
358
+ }, []);
359
+
360
+ return (
361
+ <ValidateConfigForm data={data}>
362
+ <FormView
363
+ id={formid}
364
+ formState={formState}
365
+ formErrors={formErrors}
366
+ formData={formData}
367
+ captcha={captcha}
368
+ onChangeFormData={onChangeFormData}
369
+ data={data}
370
+ onSubmit={submit}
371
+ resetFormState={resetFormState}
372
+ resetFormOnError={resetFormOnError}
373
+ getErrorMessage={getErrorMessage}
374
+ path={path}
375
+ block_id={id}
376
+ />
377
+ </ValidateConfigForm>
378
+ );
379
+ };
380
+
381
+ /**
382
+ * Property types.
383
+ * @property {Object} propTypes Property types.
384
+ * @static
385
+ */
386
+ View.propTypes = {
387
+ data: PropTypes.objectOf(PropTypes.any).isRequired,
388
+ };
389
+
390
+ export default View;