@eeacms/volto-clms-theme 1.1.260 → 1.1.262
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 +11 -0
- package/package.json +1 -1
- package/src/components/Blocks/CustomTemplates/VoltoFormBlock/View.jsx +20 -1
- package/src/components/Blocks/CustomTemplates/VoltoTabsBlock/CclProductTabsWithSubtabsView.jsx +9 -1
- package/src/customizations/volto-form-block/actions/index.js +90 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@ 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.1.262](https://github.com/eea/volto-clms-theme/compare/1.1.261...1.1.262) - 13 November 2025
|
|
8
|
+
|
|
9
|
+
#### :bug: Bug Fixes
|
|
10
|
+
|
|
11
|
+
- fix: Product pages having subtabs not positioning correctly - refs #293723 [ana-oprea - [`a564fbc`](https://github.com/eea/volto-clms-theme/commit/a564fbc6b7a5f4384c0eccf950c5dd6382963ab7)]
|
|
12
|
+
|
|
13
|
+
### [1.1.261](https://github.com/eea/volto-clms-theme/compare/1.1.260...1.1.261) - 23 October 2025
|
|
14
|
+
|
|
15
|
+
#### :hammer_and_wrench: Others
|
|
16
|
+
|
|
17
|
+
- Refs #293096 - Custom CSRF protection for our forms. Use restapi endpoint to get CSRF token and set header. [GhitaB - [`2eaba3c`](https://github.com/eea/volto-clms-theme/commit/2eaba3c52309edbe86d8be7c5c6676397c898e31)]
|
|
7
18
|
### [1.1.260](https://github.com/eea/volto-clms-theme/compare/1.1.259...1.1.260) - 10 October 2025
|
|
8
19
|
|
|
9
20
|
#### :house: Internal changes
|
package/package.json
CHANGED
|
@@ -2,7 +2,8 @@ import React, { useState, useEffect, useReducer, useRef } from 'react';
|
|
|
2
2
|
import { useSelector, useDispatch } from 'react-redux';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import { useIntl, defineMessages } from 'react-intl';
|
|
5
|
-
import { submitForm } from 'volto-form-block/actions';
|
|
5
|
+
import { submitForm } from '../../../../customizations/volto-form-block/actions';
|
|
6
|
+
|
|
6
7
|
import { getFieldName } from 'volto-form-block/components/utils';
|
|
7
8
|
import FormView from 'volto-form-block/components/FormView';
|
|
8
9
|
import { formatDate } from '@plone/volto/helpers/Utils/Date';
|
|
@@ -77,6 +78,7 @@ const View = ({ data, id, path }) => {
|
|
|
77
78
|
|
|
78
79
|
const [formState, setFormState] = useReducer(formStateReducer, initialState);
|
|
79
80
|
const [formErrors, setFormErrors] = useState([]);
|
|
81
|
+
const [csrfToken, setCsrfToken] = useState(null);
|
|
80
82
|
const submitResults = useSelector((state) => state.submitForm);
|
|
81
83
|
const captchaToken = useRef();
|
|
82
84
|
|
|
@@ -84,6 +86,22 @@ const View = ({ data, id, path }) => {
|
|
|
84
86
|
setFormData({ field, value: { field_id, value, ...extras } });
|
|
85
87
|
};
|
|
86
88
|
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
fetch(`/++api++/@clms-get-csrf-token`, {
|
|
91
|
+
credentials: 'include',
|
|
92
|
+
headers: {
|
|
93
|
+
Accept: 'application/json',
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
.then((r) => {
|
|
97
|
+
if (!r.ok) throw new Error(`${r.status} ${r.statusText}`);
|
|
98
|
+
return r.json();
|
|
99
|
+
})
|
|
100
|
+
.then((data) => {
|
|
101
|
+
setCsrfToken(data.token);
|
|
102
|
+
});
|
|
103
|
+
}, [path]);
|
|
104
|
+
|
|
87
105
|
useEffect(() => {
|
|
88
106
|
if (formErrors.length > 0) {
|
|
89
107
|
isValidForm();
|
|
@@ -204,6 +222,7 @@ const View = ({ data, id, path }) => {
|
|
|
204
222
|
})),
|
|
205
223
|
attachments,
|
|
206
224
|
captcha,
|
|
225
|
+
csrfToken,
|
|
207
226
|
),
|
|
208
227
|
);
|
|
209
228
|
setFormState({ type: FORM_STATES.loading });
|
package/src/components/Blocks/CustomTemplates/VoltoTabsBlock/CclProductTabsWithSubtabsView.jsx
CHANGED
|
@@ -124,7 +124,15 @@ const TabsComponent = ({
|
|
|
124
124
|
}, [activeTab, expandedTab, groupedTabs]);
|
|
125
125
|
|
|
126
126
|
useEffect(() => {
|
|
127
|
-
|
|
127
|
+
const urlParams = new URLSearchParams(location.search);
|
|
128
|
+
const hasHash = location.hash.length > 1;
|
|
129
|
+
const hasQueryTab = urlParams.has('tab');
|
|
130
|
+
|
|
131
|
+
if (hasHash || hasQueryTab) {
|
|
132
|
+
scrollToContentSection();
|
|
133
|
+
} else {
|
|
134
|
+
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
135
|
+
}
|
|
128
136
|
}, [activeTab, location.hash.length, location.search]);
|
|
129
137
|
|
|
130
138
|
return (
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* exportCsvFormData action
|
|
3
|
+
* @module actions/submitForm
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const SUBMIT_FORM_ACTION = 'SUBMIT_FORM_ACTION';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* submitForm function
|
|
10
|
+
* @function submitForm
|
|
11
|
+
* @param {string} path
|
|
12
|
+
* @param {string} block_id
|
|
13
|
+
* @param {Object} data
|
|
14
|
+
* @returns {Object} attachments
|
|
15
|
+
*
|
|
16
|
+
* OVERRIDED to add CSRF token for CLMS custom forms
|
|
17
|
+
*/
|
|
18
|
+
export function submitForm(
|
|
19
|
+
path = '',
|
|
20
|
+
block_id,
|
|
21
|
+
data,
|
|
22
|
+
attachments,
|
|
23
|
+
captcha,
|
|
24
|
+
csrfToken,
|
|
25
|
+
) {
|
|
26
|
+
return {
|
|
27
|
+
type: SUBMIT_FORM_ACTION,
|
|
28
|
+
request: {
|
|
29
|
+
op: 'post',
|
|
30
|
+
path: path + '/@submit-form',
|
|
31
|
+
headers: {
|
|
32
|
+
'X-CSRF-TOKEN': csrfToken,
|
|
33
|
+
},
|
|
34
|
+
data: {
|
|
35
|
+
block_id,
|
|
36
|
+
data,
|
|
37
|
+
attachments,
|
|
38
|
+
captcha,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* exportCsvFormData action
|
|
46
|
+
* @module actions/exportCsvFormData
|
|
47
|
+
*/
|
|
48
|
+
export const EXPORT_CSV_FORMDATA = 'EXPORT_CSV_FORMDATA';
|
|
49
|
+
|
|
50
|
+
export function exportCsvFormData(path = '') {
|
|
51
|
+
return {
|
|
52
|
+
type: EXPORT_CSV_FORMDATA,
|
|
53
|
+
request: {
|
|
54
|
+
op: 'get',
|
|
55
|
+
path: path + '/@form-data-export',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* getFormData action
|
|
62
|
+
* @module actions/getFormData
|
|
63
|
+
*/
|
|
64
|
+
export const GET_FORM_DATA = 'GET_FORMDATA';
|
|
65
|
+
|
|
66
|
+
export function getFormData(path = '') {
|
|
67
|
+
return {
|
|
68
|
+
type: GET_FORM_DATA,
|
|
69
|
+
request: {
|
|
70
|
+
op: 'get',
|
|
71
|
+
path: path + '/@form-data',
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* clearFormData action
|
|
78
|
+
* @module actions/getFormData
|
|
79
|
+
*/
|
|
80
|
+
export const CLEAR_FORM_DATA = 'CLEAR_FORM_DATA';
|
|
81
|
+
|
|
82
|
+
export function clearFormData(path = '') {
|
|
83
|
+
return {
|
|
84
|
+
type: CLEAR_FORM_DATA,
|
|
85
|
+
request: {
|
|
86
|
+
op: 'get',
|
|
87
|
+
path: path + '/@form-data-clear',
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|