@eeacms/volto-cca-policy 0.3.107 → 0.3.108

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,12 @@ 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
+ ### [0.3.108](https://github.com/eea/volto-cca-policy/compare/0.3.107...0.3.108) - 31 March 2026
8
+
9
+ #### :bug: Bug Fixes
10
+
11
+ - fix: active state in collection stats block, style improvements - refs #269021 [kreafox - [`408ec1c`](https://github.com/eea/volto-cca-policy/commit/408ec1cec816f626af0b14fe45fde3094ea9aafc)]
12
+
7
13
  ### [0.3.107](https://github.com/eea/volto-cca-policy/compare/0.3.106...0.3.107) - 30 March 2026
8
14
 
9
15
  #### :rocket: New Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-cca-policy",
3
- "version": "0.3.107",
3
+ "version": "0.3.108",
4
4
  "description": "@eeacms/volto-cca-policy: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { useSelector, useDispatch } from 'react-redux';
3
+ import { useLocation } from 'react-router-dom';
3
4
  import { getQueryStats } from '@eeacms/volto-cca-policy/store';
4
5
  import { getBaseUrl as getBase } from '@eeacms/volto-cca-policy/utils';
5
6
  import { getBaseUrl } from '@plone/volto/helpers';
@@ -25,7 +26,8 @@ const useStats = (path, id, data) => {
25
26
 
26
27
  export const StatVoltoIcon = ({ name, value, source, showLabel = false }) => {
27
28
  const intl = useIntl();
28
- const label = intl.formatMessage({ id: name });
29
+ const label = intl.formatMessage({ id: name, defaultMessage: name });
30
+
29
31
  return (
30
32
  <div className="tab-icon" title={label}>
31
33
  <div className="tab-icon-wrapper">
@@ -41,6 +43,7 @@ export const StatVoltoIcon = ({ name, value, source, showLabel = false }) => {
41
43
  export const RemixIcon = ({ name, value, source, showLabel = false }) => {
42
44
  const intl = useIntl();
43
45
  const label = intl.formatMessage({ id: name, defaultMessage: name });
46
+
44
47
  return (
45
48
  <div className="tab-icon semantic-icon" title={label}>
46
49
  <div className="tab-icon-wrapper">
@@ -52,7 +55,7 @@ export const RemixIcon = ({ name, value, source, showLabel = false }) => {
52
55
  );
53
56
  };
54
57
 
55
- const makeSearchBlockQuery = ({ base, query, field, value }) => {
58
+ const makeSearchBlockQuery = ({ base, query = [], field, value }) => {
56
59
  const filtered = [
57
60
  ...query.filter(({ i }) => i !== field),
58
61
  {
@@ -61,8 +64,8 @@ const makeSearchBlockQuery = ({ base, query, field, value }) => {
61
64
  v: [value],
62
65
  },
63
66
  ];
64
- const params = qs.stringify({ query: JSON.stringify(filtered) });
65
67
 
68
+ const params = qs.stringify({ query: JSON.stringify(filtered) });
66
69
  return `${base}?${params}`;
67
70
  };
68
71
 
@@ -103,17 +106,48 @@ function remapItemTypeValue(val) {
103
106
  'Publication and report': 'Publication reference',
104
107
  'Video and podcast': 'Video',
105
108
  };
106
- if (val in list) {
107
- return list[val];
109
+
110
+ return list[val] || val;
111
+ }
112
+
113
+ function getActiveFilters(locationSearch) {
114
+ try {
115
+ const params = new URLSearchParams(locationSearch);
116
+ const queryParam = params.get('query');
117
+ if (!queryParam) return [];
118
+
119
+ const parsed = JSON.parse(queryParam);
120
+ return Array.isArray(parsed) ? parsed : [];
121
+ } catch (e) {
122
+ return [];
108
123
  }
109
- return val;
124
+ }
125
+
126
+ function isFilterActive(activeFilters, field, value) {
127
+ return activeFilters.some(
128
+ (f) =>
129
+ f?.i === field &&
130
+ Array.isArray(f?.v) &&
131
+ f.v.includes(value) &&
132
+ f?.o === 'plone.app.querystring.operation.selection.any',
133
+ );
110
134
  }
111
135
 
112
136
  export default function CollectionStatsView(props) {
113
137
  const { id, data = {}, pathname = props.path } = props;
114
- const field = data.aggregateField?.value;
138
+ const field =
139
+ typeof data.aggregateField === 'string'
140
+ ? data.aggregateField
141
+ : data.aggregateField?.value;
142
+
115
143
  const { queryParameterStyle = 'SearchBlock', query = {}, showLabel } = data;
116
144
  const base = getBase(props);
145
+ const location = useLocation();
146
+ const activeFilters = React.useMemo(
147
+ () => getActiveFilters(location.search),
148
+ [location.search],
149
+ );
150
+
117
151
  let stats = useStats(getBaseUrl(pathname), id, data);
118
152
  const intl = useIntl();
119
153
 
@@ -128,26 +162,37 @@ export default function CollectionStatsView(props) {
128
162
  const extraFilters = data?.extraFilters || [];
129
163
 
130
164
  return (
131
- (field && keys.length > 0 && (
165
+ (field && keys.length > 0 && IconComponent && (
132
166
  <div className="collection-stats">
133
167
  {keys
134
168
  .sort((a, b) => a.localeCompare(b))
135
169
  .map((k) => {
136
- let kV = remapItemTypeValue(k);
170
+ const kV = remapItemTypeValue(k);
171
+ const currentField = groupDefinition.searchFieldName || field;
172
+ const currentValue = intl.formatMessage({
173
+ id: kV,
174
+ defaultMessage: kV,
175
+ });
176
+
177
+ const href = urlHandler({
178
+ base,
179
+ query: query.query,
180
+ field: currentField,
181
+ value: currentValue,
182
+ extraFilters,
183
+ });
184
+
185
+ const active = isFilterActive(
186
+ activeFilters,
187
+ currentField,
188
+ currentValue,
189
+ );
190
+
137
191
  return (
138
192
  <UniversalLink
139
- className="tab-item-link"
193
+ className={`tab-item-link ${active ? 'active' : ''}`}
140
194
  key={k}
141
- href={urlHandler({
142
- base,
143
- query: query.query,
144
- field: groupDefinition.searchFieldName || field,
145
- value: intl.formatMessage({
146
- id: kV,
147
- defaultMessage: kV,
148
- }),
149
- extraFilters,
150
- })}
195
+ href={href}
151
196
  >
152
197
  <IconComponent
153
198
  name={k}
@@ -33,14 +33,23 @@ body.cca-main-homepage {
33
33
  display: inline-block;
34
34
  }
35
35
 
36
- .tab-item-link:hover {
37
- .count {
38
- background-color: @ccaGreenColor;
36
+ .tab-item-link {
37
+ &:hover,
38
+ &.active {
39
+ .count {
40
+ background-color: @ccaGreenColor;
41
+ }
42
+
43
+ .tab-icon,
44
+ .label {
45
+ color: @primaryColor;
46
+ }
39
47
  }
40
48
 
41
- .tab-icon,
42
- .label {
43
- color: @primaryColor;
49
+ &.active {
50
+ .label {
51
+ font-weight: 500;
52
+ }
44
53
  }
45
54
  }
46
55
 
@@ -154,3 +154,22 @@
154
154
  }
155
155
  }
156
156
  }
157
+
158
+ #main .block.search {
159
+ .ui.accordion.filter-listing {
160
+ .filter-list-content {
161
+ padding: 0.5em 1em !important;
162
+ margin-top: 0.5em;
163
+ background: none;
164
+ }
165
+
166
+ .filter-list-group {
167
+ margin: 0;
168
+
169
+ .label {
170
+ color: inherit;
171
+ border-color: #eaeaea;
172
+ }
173
+ }
174
+ }
175
+ }