@eeacms/volto-clms-theme 1.0.132 → 1.0.133

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ ### [1.0.133](https://github.com/eea/volto-clms-theme/compare/1.0.132...1.0.133) - 6 October 2022
8
+
9
+ #### :bug: Bug Fixes
10
+
11
+ - fix: remove padding from datset download table segment [joewdavies - [`323857c`](https://github.com/eea/volto-clms-theme/commit/323857c3c4f02e31e6bae880b9c4feda7807932e)]
12
+ - fix: hash for FAQ tabs [ionlizarazu - [`10621d1`](https://github.com/eea/volto-clms-theme/commit/10621d15f2a83405d60109874e0a03798873de28)]
13
+ - fix: tabs hash with search inside CLMS-1438 [ionlizarazu - [`1cea1b0`](https://github.com/eea/volto-clms-theme/commit/1cea1b0b8dc772e6ca2beb8831f6625f8a58166e)]
14
+ - fix: fields order for the email in volto-form-block [ionlizarazu - [`798dcb3`](https://github.com/eea/volto-clms-theme/commit/798dcb38defe79924ba5b1aa4eace10d99235bcb)]
15
+ - fix: manage the image_field_widget as attachment [ionlizarazu - [`c93869f`](https://github.com/eea/volto-clms-theme/commit/c93869f9d3e05f7dba4be7398d73b7dae9b276b5)]
16
+ - fix: CLMS-1424 remove word-break from cart table cells to prevent compaction [joewdavies - [`8b43cb0`](https://github.com/eea/volto-clms-theme/commit/8b43cb0486597c82d25c5e547801da4645706bdd)]
17
+
18
+ #### :hammer_and_wrench: Others
19
+
20
+ - override and use our volto-form-block View.jsx [ionlizarazu - [`f47511a`](https://github.com/eea/volto-clms-theme/commit/f47511a5c50b82d411e9b3c4fe45287f728bca17)]
7
21
  ### [1.0.132](https://github.com/eea/volto-clms-theme/compare/1.0.131...1.0.132) - 3 October 2022
8
22
 
9
23
  #### :rocket: New Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-clms-theme",
3
- "version": "1.0.132",
3
+ "version": "1.0.133",
4
4
  "description": "volto-clms-theme: Volto theme for CLMS site",
5
5
  "main": "src/index.js",
6
6
  "author": "CodeSyntax for the European Environment Agency",
@@ -0,0 +1,274 @@
1
+ import React, { useState, useEffect, useReducer, useRef } from 'react';
2
+ import { useSelector, useDispatch } from 'react-redux';
3
+ import PropTypes from 'prop-types';
4
+ import { useIntl, defineMessages } from 'react-intl';
5
+ import { submitForm } from 'volto-form-block/actions';
6
+ import { getFieldName } from 'volto-form-block/components/utils';
7
+ import FormView from 'volto-form-block/components/FormView';
8
+ import { formatDate } from '@plone/volto/helpers/Utils/Date';
9
+ import config from '@plone/volto/registry';
10
+ import Captcha from 'volto-form-block/components/Widget/Captcha';
11
+
12
+ const messages = defineMessages({
13
+ formSubmitted: {
14
+ id: 'formSubmitted',
15
+ defaultMessage: 'Form successfully submitted',
16
+ },
17
+ });
18
+
19
+ const initialState = {
20
+ loading: false,
21
+ error: null,
22
+ result: null,
23
+ };
24
+
25
+ const FORM_STATES = {
26
+ normal: 'normal',
27
+ loading: 'loading',
28
+ error: 'error',
29
+ success: 'success',
30
+ };
31
+
32
+ const formStateReducer = (state, action) => {
33
+ switch (action.type) {
34
+ case FORM_STATES.normal:
35
+ return initialState;
36
+
37
+ case FORM_STATES.loading:
38
+ return { loading: true, error: null, result: null };
39
+
40
+ case FORM_STATES.error:
41
+ return { loading: false, error: action.error, result: null };
42
+
43
+ case FORM_STATES.success:
44
+ return { loading: false, error: null, result: action.result };
45
+
46
+ default:
47
+ return initialState;
48
+ }
49
+ };
50
+
51
+ const getInitialData = (data) => ({
52
+ ...data.reduce(
53
+ (acc, field) => ({ ...acc, [getFieldName(field.label, field.id)]: field }),
54
+ {},
55
+ ),
56
+ });
57
+
58
+ /**
59
+ * Form view
60
+ * @class View
61
+ */
62
+ const View = ({ data, id, path }) => {
63
+ const intl = useIntl();
64
+ const dispatch = useDispatch();
65
+ const { static_fields = [] } = data;
66
+
67
+ const [formData, setFormData] = useReducer((state, action) => {
68
+ if (action.reset) {
69
+ return getInitialData(static_fields);
70
+ }
71
+
72
+ return {
73
+ ...state,
74
+ [action.field]: action.value,
75
+ };
76
+ }, getInitialData(static_fields));
77
+
78
+ const [formState, setFormState] = useReducer(formStateReducer, initialState);
79
+ const [formErrors, setFormErrors] = useState([]);
80
+ const submitResults = useSelector((state) => state.submitForm);
81
+ const captchaToken = useRef();
82
+
83
+ const onChangeFormData = (field_id, field, value, extras) => {
84
+ setFormData({ field, value: { field_id, value, ...extras } });
85
+ };
86
+
87
+ useEffect(() => {
88
+ if (formErrors.length > 0) {
89
+ isValidForm();
90
+ }
91
+ // eslint-disable-next-line react-hooks/exhaustive-deps
92
+ }, [formData]);
93
+
94
+ const isValidForm = () => {
95
+ const v = [];
96
+ data.subblocks.forEach((subblock, index) => {
97
+ const name = getFieldName(subblock.label, subblock.id);
98
+ const fieldType = subblock.field_type;
99
+ const additionalField =
100
+ config.blocks.blocksConfig.form.additionalFields?.filter(
101
+ (f) => f.id === fieldType && f.isValid !== undefined,
102
+ )?.[0] ?? null;
103
+ if (
104
+ subblock.required &&
105
+ additionalField &&
106
+ !additionalField?.isValid(formData, name)
107
+ ) {
108
+ v.push(name);
109
+ } else if (
110
+ subblock.required &&
111
+ fieldType === 'checkbox' &&
112
+ !formData[name]?.value
113
+ ) {
114
+ v.push(name);
115
+ } else if (
116
+ subblock.required &&
117
+ (!formData[name] ||
118
+ formData[name]?.value?.length === 0 ||
119
+ JSON.stringify(formData[name]?.value ?? {}) === '{}')
120
+ ) {
121
+ v.push(name);
122
+ }
123
+ });
124
+
125
+ if (data.captcha && !captchaToken.current) {
126
+ v.push('captcha');
127
+ }
128
+
129
+ setFormErrors(v);
130
+ return v.length === 0;
131
+ };
132
+
133
+ const submit = (e) => {
134
+ e.preventDefault();
135
+ captcha
136
+ .verify()
137
+ .then(() => {
138
+ if (isValidForm()) {
139
+ let attachments = {};
140
+ let captcha = {
141
+ provider: data.captcha,
142
+ token: captchaToken.current,
143
+ };
144
+ if (data.captcha === 'honeypot') {
145
+ captcha.value = formData[data.captcha_props.id]?.value ?? '';
146
+ }
147
+
148
+ let formattedFormData = { ...formData };
149
+ data.subblocks.forEach((subblock) => {
150
+ let name = getFieldName(subblock.label, subblock.id);
151
+ if (formattedFormData[name]?.value) {
152
+ formattedFormData[name].field_id = subblock.field_id;
153
+ // const isAttachment = subblock.field_type === 'attachment';
154
+ const isAttachment = [
155
+ 'attachment',
156
+ 'image_field_widget',
157
+ ].includes(subblock.field_type);
158
+ const isDate = subblock.field_type === 'date';
159
+
160
+ if (isAttachment) {
161
+ attachments[name] = formattedFormData[name].value;
162
+ delete formattedFormData[name];
163
+ }
164
+
165
+ if (isDate) {
166
+ formattedFormData[name].value = formatDate({
167
+ date: formattedFormData[name].value,
168
+ format: 'DD-MM-YYYY',
169
+ locale: intl.locale,
170
+ });
171
+ }
172
+ }
173
+ });
174
+
175
+ const sortedFormattedFormData = Object.keys(formattedFormData)
176
+ .sort((a, b) => {
177
+ return (
178
+ data.subblocks
179
+ .map((subblock) => getFieldName(subblock.label, subblock.id))
180
+ .indexOf(a) -
181
+ data.subblocks
182
+ .map((subblock) => getFieldName(subblock.label, subblock.id))
183
+ .indexOf(b)
184
+ );
185
+ })
186
+ .reduce((accumulator, key) => {
187
+ accumulator[key] = formattedFormData[key];
188
+
189
+ return accumulator;
190
+ }, {});
191
+ dispatch(
192
+ submitForm(
193
+ path,
194
+ id,
195
+ Object.keys(sortedFormattedFormData).map((name) => ({
196
+ ...sortedFormattedFormData[name],
197
+ })),
198
+ attachments,
199
+ captcha,
200
+ ),
201
+ );
202
+ setFormState({ type: FORM_STATES.loading });
203
+ } else {
204
+ setFormState({ type: FORM_STATES.error });
205
+ }
206
+ })
207
+ .catch(() => {
208
+ setFormState({ type: FORM_STATES.error });
209
+ });
210
+ };
211
+
212
+ const resetFormState = () => {
213
+ setFormData({ reset: true });
214
+ setFormState({ type: FORM_STATES.normal });
215
+ };
216
+
217
+ const resetFormOnError = () => {
218
+ setFormState({ type: FORM_STATES.normal });
219
+ };
220
+
221
+ const captcha = new Captcha({
222
+ captchaToken,
223
+ captcha: data.captcha,
224
+ captcha_props: data.captcha_props,
225
+ onChangeFormData,
226
+ });
227
+
228
+ useEffect(() => {
229
+ if (submitResults?.loaded) {
230
+ setFormState({
231
+ type: FORM_STATES.success,
232
+ result: intl.formatMessage(messages.formSubmitted),
233
+ });
234
+ captcha.reset();
235
+ } else if (submitResults?.error) {
236
+ let errorDescription = `${
237
+ JSON.parse(submitResults.error.response?.text ?? '{}')?.message
238
+ }`;
239
+
240
+ setFormState({ type: FORM_STATES.error, error: errorDescription });
241
+ }
242
+ captchaToken.current = undefined;
243
+ // eslint-disable-next-line react-hooks/exhaustive-deps
244
+ }, [submitResults]);
245
+
246
+ useEffect(() => {
247
+ resetFormState();
248
+ }, []);
249
+
250
+ return (
251
+ <FormView
252
+ formState={formState}
253
+ formErrors={formErrors}
254
+ formData={formData}
255
+ captcha={captcha}
256
+ onChangeFormData={onChangeFormData}
257
+ data={data}
258
+ onSubmit={submit}
259
+ resetFormState={resetFormState}
260
+ resetFormOnError={resetFormOnError}
261
+ />
262
+ );
263
+ };
264
+
265
+ /**
266
+ * Property types.
267
+ * @property {Object} propTypes Property types.
268
+ * @static
269
+ */
270
+ View.propTypes = {
271
+ data: PropTypes.objectOf(PropTypes.any).isRequired,
272
+ };
273
+
274
+ export default View;
@@ -25,7 +25,7 @@ const CclVerticalFaqTabsView = (props) => {
25
25
  <div className="right-content cont-w-75">
26
26
  {tabsList.map((tab, index) => {
27
27
  const title = tabs[tab].title;
28
- const tabHash = slugify(title);
28
+ const tabHash = `tab=${slugify(title)}`;
29
29
  return (
30
30
  <Route to={'#' + tabHash}>
31
31
  <div
@@ -64,7 +64,7 @@ const CclVerticalFaqTabsView = (props) => {
64
64
  const nextSubTab =
65
65
  tabs[tabsList[tabIndex]]?.subTab?.subtab || false;
66
66
  const defaultTitle = `Tab ${tabIndex}`;
67
- const tabHash = title.split(' ').join('-');
67
+ const tabHash = `tab=${slugify(title)}`;
68
68
  return (
69
69
  <div
70
70
  key={index}
@@ -37,7 +37,7 @@ const CclVerticalTabsView = (props) => {
37
37
  <div className="right-content cont-w-75">
38
38
  {tabsList.map((tab, index) => {
39
39
  const title = tabs[tab].title;
40
- const tabHash = slugify(title);
40
+ const tabHash = `tab=${slugify(title)}`;
41
41
  return (
42
42
  <Route key={index} to={'#' + tabHash}>
43
43
  <div
@@ -70,7 +70,7 @@ const CclVerticalTabsView = (props) => {
70
70
  const nextSubTab =
71
71
  tabs[tabsList[tabIndex]]?.subTab?.subtab || false;
72
72
  const defaultTitle = `Tab ${tabIndex}`;
73
- const tabHash = slugify(title);
73
+ const tabHash = `tab=${slugify(title)}`;
74
74
  return (
75
75
  <div
76
76
  key={index}
@@ -29,12 +29,12 @@ const RoutingHOC = (TabView) =>
29
29
  // return rTabsList[window.location.hash.match(/.*&?#?tab=(.*)/)[1] - 1];
30
30
  // }
31
31
  if (
32
- window.location.hash.match(/.*&?(#.*)/) &&
33
- window.location.hash.match(/.*&?(#.*)/).length > 1
32
+ window.location.hash.match(/.*([&|#]tab=.*)/) &&
33
+ window.location.hash.match(/.*([&|#]tab=.*)/).length > 1
34
34
  ) {
35
35
  const hashMatch = window.location.hash
36
- .match(/.*&?(#.*)/)[1]
37
- .replace('#', '');
36
+ .match(/.*([&|#]tab=.*)/)[1]
37
+ .replace(/[&|#]tab=/, '');
38
38
  const result = tabsDict.filter((t) => slugify(t.title) === hashMatch);
39
39
  if (result.length > 0) {
40
40
  return result[0].id;
@@ -74,7 +74,7 @@ import ImageWidget from '@eeacms/volto-clms-theme/components/Widgets/ImageWidget
74
74
  import TextWidget from '@plone/volto/components/manage/Widgets/TextWidget';
75
75
  import TextareaWidget from '@plone/volto/components/manage/Widgets/TextareaWidget';
76
76
  import EmailWidget from '@plone/volto/components/manage/Widgets/EmailWidget';
77
-
77
+ import { default as FormCustomView } from '@eeacms/volto-clms-theme/components/Blocks/CustomTemplates/VoltoFormBlock/View';
78
78
  export const customGroupBlocksOrder = [
79
79
  {
80
80
  id: 'ccl_blocks',
@@ -481,6 +481,7 @@ const customBlocks = (config) => ({
481
481
  },
482
482
  form: {
483
483
  ...config.blocks.blocksConfig.form,
484
+ view: FormCustomView,
484
485
  fieldSchema: customIdFieldSchema,
485
486
  fieldTypeSchemaExtenders: {
486
487
  checkbox_html: CheckboxSchemaExtender,
@@ -940,6 +940,11 @@ body:not(.contenttype-lrf:not(.section-cart):not(.section-profile))
940
940
  vertical-align: middle;
941
941
  }
942
942
 
943
+ .dataset-download-table > .ui.basic.segment {
944
+ padding-left: 0px;
945
+ padding-right: 0px;
946
+ }
947
+
943
948
  /* Downloads */
944
949
  .download-block {
945
950
  position: relative;
@@ -1251,4 +1256,9 @@ div#page-document h1.documentFirstHeading {
1251
1256
  #sidebar-metadata .react-select__option {
1252
1257
  white-space: nowrap;
1253
1258
  width: fit-content;
1259
+ }
1260
+
1261
+ // CLMS-1424
1262
+ .cart-table td {
1263
+ word-break: unset !important;
1254
1264
  }