@eeacms/volto-cca-policy 0.3.84 → 0.3.86

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,7 +4,7 @@ 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.84](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.1...0.3.84) - 7 October 2025
7
+ ### [0.3.86](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.1...0.3.86) - 31 October 2025
8
8
 
9
9
  #### :rocket: Dependency updates
10
10
 
@@ -14,12 +14,21 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
14
14
 
15
15
  #### :bug: Bug Fixes
16
16
 
17
+ - fix(tests): increase code coverage [kreafox - [`66cd2b3`](https://github.com/eea/volto-cca-policy/commit/66cd2b39a9b7b026c171d99e2bf3b8a47b7cddd2)]
18
+ - fix(tests): update hyperlink text in PlanningTab [kreafox - [`05080e0`](https://github.com/eea/volto-cca-policy/commit/05080e0727730a5fe7c67d884ad6453eaf82081a)]
19
+ - fix(mission): adjust margins for nested lists and accordion padding [kreafox - [`1abf18f`](https://github.com/eea/volto-cca-policy/commit/1abf18fabe9efffa552ed2e6a8b57f9b1d59f7a6)]
20
+ - fix(mission): improve URL extraction logic - refs #291190 [kreafox - [`8e4c6e4`](https://github.com/eea/volto-cca-policy/commit/8e4c6e42dc35b4c940c39f9f25d587f66d0b242d)]
21
+ - fix(mission): fix assessment risk numbering to match sorted order [kreafox - [`9ecea88`](https://github.com/eea/volto-cca-policy/commit/9ecea885394f1ae6ad63ffb03d8a10cd706caffb)]
17
22
  - fix: duplicated code - make ItemsSection reusable [kreafox - [`52e2625`](https://github.com/eea/volto-cca-policy/commit/52e2625914f699c194f75d561f97959ab6c21fbf)]
18
23
  - fix: add missing props for title block [kreafox - [`1d8efa0`](https://github.com/eea/volto-cca-policy/commit/1d8efa0136960261196e7585f89f4ff7db75ae17)]
19
24
  - fix: trailing space issue in HtmlSlateWidget - refs #290137 [kreafox - [`34c1ff6`](https://github.com/eea/volto-cca-policy/commit/34c1ff6896a0fe3fae40527f31ea34220e945163)]
20
25
 
21
26
  #### :nail_care: Enhancements
22
27
 
28
+ - change(mission): add third level for sectors and hazards - refs #291189 [kreafox - [`5cf352c`](https://github.com/eea/volto-cca-policy/commit/5cf352ce46284b3cbd106276b60a1d4fea89235d)]
29
+ - refactor(mission): simplify sector rendering logic in Action tab [kreafox - [`8413ccc`](https://github.com/eea/volto-cca-policy/commit/8413cccfd67e9a598f88474b8a034e7998063d23)]
30
+ - change(mission): improve AccordionList [kreafox - [`cf1497f`](https://github.com/eea/volto-cca-policy/commit/cf1497ff50ff45cdb0bb8e995683969bb3e3c065)]
31
+ - refactor(mission): remove unnecessary line breaks and simplify message rendering - refs #291190 [kreafox - [`430a123`](https://github.com/eea/volto-cca-policy/commit/430a12371b6e1c6a77ea65b6a434eda883568c64)]
23
32
  - refactor(mission): use ItemsSection in PlanningTab - refs #291190 [kreafox - [`9e96aaa`](https://github.com/eea/volto-cca-policy/commit/9e96aaac0686f6688b3406aca578b598882a9c29)]
24
33
  - change: update sectors with icons for Planning tab - refs #291190 [kreafox - [`8b82168`](https://github.com/eea/volto-cca-policy/commit/8b821686fc6b9d98c542d9f0315734b446070a17)]
25
34
  - change: update factors with icons for Assessment tab - refs #291189 [kreafox - [`d8b7afc`](https://github.com/eea/volto-cca-policy/commit/d8b7afc36b2129b60ef81d9a057c4c9be35cbb03)]
@@ -37,6 +46,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
37
46
 
38
47
  #### :hammer_and_wrench: Others
39
48
 
49
+ - test: try to use specific version for plone-backend [kreafox - [`79c542e`](https://github.com/eea/volto-cca-policy/commit/79c542e8d55d2f1663b768c555880599634ae527)]
50
+ - test(mission): add unit tests for NoDataReported and StatisticSection components [kreafox - [`36c6e36`](https://github.com/eea/volto-cca-policy/commit/36c6e36278124759240c896786f2ac0c20674730)]
40
51
  - test: resolve Jest errors in component tests [kreafox - [`6dbb735`](https://github.com/eea/volto-cca-policy/commit/6dbb73540e8301fcb42a4d52db7004f5a42db4d8)]
41
52
  - test: fix PlanningTab mock data to match component structure [kreafox - [`48e76e1`](https://github.com/eea/volto-cca-policy/commit/48e76e1e50e0c6d8a6a500fec3d1831419faeee9)]
42
53
  - test: resolve Jest errors in component tests [kreafox - [`f309b96`](https://github.com/eea/volto-cca-policy/commit/f309b96b0767358530d969e21102887a9db76b5a)]
@@ -125,8 +136,47 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
125
136
  - Add some loadable for components [Tiberiu Ichim - [`1793962`](https://github.com/eea/volto-cca-policy/commit/179396211c66a6a2465b2d1b6c0f2afc40fc7189)]
126
137
  - Refs #284961 - test [Tripon Eugen - [`c989f1f`](https://github.com/eea/volto-cca-policy/commit/c989f1f8638c0c5233c5c49f8673c9a2cdc7937e)]
127
138
  - Refs #284961 - add translations [Tripon Eugen - [`04ee988`](https://github.com/eea/volto-cca-policy/commit/04ee988c086d393b9b37ce1ea8d24f5e84f266aa)]
128
- ### [1.0.0-alpha.0](https://github.com/eea/volto-cca-policy/compare/0.3.83...1.0.0-alpha.0) - 15 July 2025
139
+ ### [1.0.0-alpha.0](https://github.com/eea/volto-cca-policy/compare/0.3.85...1.0.0-alpha.0) - 15 July 2025
129
140
 
141
+ ### [0.3.85](https://github.com/eea/volto-cca-policy/compare/0.3.84...0.3.85) - 14 October 2025
142
+
143
+ #### :bug: Bug Fixes
144
+
145
+ - fix(mission): fix assessment risk numbering to match sorted order [kreafox - [`9ecea88`](https://github.com/eea/volto-cca-policy/commit/9ecea885394f1ae6ad63ffb03d8a10cd706caffb)]
146
+
147
+ #### :nail_care: Enhancements
148
+
149
+ - change(mission): improve AccordionList [kreafox - [`cf1497f`](https://github.com/eea/volto-cca-policy/commit/cf1497ff50ff45cdb0bb8e995683969bb3e3c065)]
150
+ - refactor(mission): remove unnecessary line breaks and simplify message rendering - refs #291190 [kreafox - [`430a123`](https://github.com/eea/volto-cca-policy/commit/430a12371b6e1c6a77ea65b6a434eda883568c64)]
151
+
152
+ #### :hammer_and_wrench: Others
153
+
154
+ - test(mission): add unit tests for NoDataReported and StatisticSection components [kreafox - [`36c6e36`](https://github.com/eea/volto-cca-policy/commit/36c6e36278124759240c896786f2ac0c20674730)]
155
+ ### [0.3.84](https://github.com/eea/volto-cca-policy/compare/0.3.83...0.3.84) - 7 October 2025
156
+
157
+ #### :bug: Bug Fixes
158
+
159
+ - fix: duplicated code - make ItemsSection reusable [kreafox - [`52e2625`](https://github.com/eea/volto-cca-policy/commit/52e2625914f699c194f75d561f97959ab6c21fbf)]
160
+
161
+ #### :nail_care: Enhancements
162
+
163
+ - refactor(mission): use ItemsSection in PlanningTab - refs #291190 [kreafox - [`9e96aaa`](https://github.com/eea/volto-cca-policy/commit/9e96aaac0686f6688b3406aca578b598882a9c29)]
164
+ - change: update sectors with icons for Planning tab - refs #291190 [kreafox - [`8b82168`](https://github.com/eea/volto-cca-policy/commit/8b821686fc6b9d98c542d9f0315734b446070a17)]
165
+ - change: update factors with icons for Assessment tab - refs #291189 [kreafox - [`d8b7afc`](https://github.com/eea/volto-cca-policy/commit/d8b7afc36b2129b60ef81d9a057c4c9be35cbb03)]
166
+ - change: update sectors with icons for Action tab - refs #291188 [kreafox - [`a9f15c7`](https://github.com/eea/volto-cca-policy/commit/a9f15c70fa261c9da5b0f01d0bf07ede0136085f)]
167
+ - change(mission): use result_beta in sandbox for signatory reporting - refs #292508 [kreafox - [`b425801`](https://github.com/eea/volto-cca-policy/commit/b42580100bdd2b4d79be53bbfa05098856deb4be)]
168
+ - change: update signatory profile action tab with icons [kreafox - [`0e72902`](https://github.com/eea/volto-cca-policy/commit/0e7290259b966ff72d2a4d77efca8fbeec8655f8)]
169
+
170
+ #### :house: Internal changes
171
+
172
+ - style(mission): mobile fixes on signatory reporting pages [kreafox - [`cbeb584`](https://github.com/eea/volto-cca-policy/commit/cbeb5846c8047c164c29635bd30491b4f810246a)]
173
+ - chore: better component naming [kreafox - [`d61e462`](https://github.com/eea/volto-cca-policy/commit/d61e4629da184ec14d6ad0d056ac29751223e2f9)]
174
+
175
+ #### :hammer_and_wrench: Others
176
+
177
+ - test: resolve Jest errors in component tests [kreafox - [`6dbb735`](https://github.com/eea/volto-cca-policy/commit/6dbb73540e8301fcb42a4d52db7004f5a42db4d8)]
178
+ - test: fix PlanningTab mock data to match component structure [kreafox - [`48e76e1`](https://github.com/eea/volto-cca-policy/commit/48e76e1e50e0c6d8a6a500fec3d1831419faeee9)]
179
+ - test: resolve Jest errors in component tests [kreafox - [`f309b96`](https://github.com/eea/volto-cca-policy/commit/f309b96b0767358530d969e21102887a9db76b5a)]
130
180
  ### [0.3.83](https://github.com/eea/volto-cca-policy/compare/0.3.82...0.3.83) - 10 September 2025
131
181
 
132
182
  #### :hammer_and_wrench: Others
@@ -207,7 +257,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
207
257
  - style: fix item spacing [kreafox - [`7d4535d`](https://github.com/eea/volto-cca-policy/commit/7d4535dbc486e6cb80fc55d6ac8c7c01d9cf48af)]
208
258
  - chore: code cleanup [kreafox - [`842419b`](https://github.com/eea/volto-cca-policy/commit/842419b1bce3dc624755c81c9dea672198cab9e2)]
209
259
  - style: update teaser block styling [kreafox - [`1e0cad8`](https://github.com/eea/volto-cca-policy/commit/1e0cad8e1ed3ae827ee868dce8ad50b292a937ba)]
210
- - chore: update Makefile, run yarn i18n [kreafox - [`61e6962`](https://github.com/eea/volto-cca-policy/commit/61e6962901068ae6512265417a730bd9befd65fe)]
211
260
  - chore: move styling to theme folder [kreafox - [`8cf6a1b`](https://github.com/eea/volto-cca-policy/commit/8cf6a1b8b14abf472a9c61b28db574f6d9e0bd3b)]
212
261
  - chore: remove ArrayWidget customization [kreafox - [`249bf93`](https://github.com/eea/volto-cca-policy/commit/249bf93054f7726c3d57a8b8ca01b75cd0d30522)]
213
262
  - chore: remove Footer customization [kreafox - [`7038af3`](https://github.com/eea/volto-cca-policy/commit/7038af37d48a328dfc31746f3fa84973e2f840ab)]
@@ -2970,13 +3019,10 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
2970
3019
  - Refs #260715 rast-block wip [Tripon Eugen - [`f19d54e`](https://github.com/eea/volto-cca-policy/commit/f19d54e0b9a6a86bf344eb85b6a1cda7f3de91bf)]
2971
3020
  - Refs #260715 rast-block wip [Tripon Eugen - [`2828537`](https://github.com/eea/volto-cca-policy/commit/2828537b6c084cd1a82162d552fb4ef025b71f9f)]
2972
3021
  - Refs #260715 rast-block updates [Tripon Eugen - [`1e803e5`](https://github.com/eea/volto-cca-policy/commit/1e803e5bd3d3fb7558f261c76c68866be7beb8b5)]
2973
- - test: [JENKINS] Use java17 for sonarqube scanner [valentinab25 - [`0a15e1b`](https://github.com/eea/volto-cca-policy/commit/0a15e1b2ad081233685e80d5b3c60a8663f6b896)]
2974
- - test: [JENKINS] Run cypress in started frontend container [valentinab25 - [`9554e44`](https://github.com/eea/volto-cca-policy/commit/9554e44c92a621a52b2adb5a4830fb084ee5734b)]
2975
3022
  ### [0.1.49](https://github.com/eea/volto-cca-policy/compare/0.1.48...0.1.49) - 15 November 2023
2976
3023
 
2977
3024
  #### :house: Internal changes
2978
3025
 
2979
- - chore: [JENKINS] Refactor automated testing [valentinab25 - [`7b820a6`](https://github.com/eea/volto-cca-policy/commit/7b820a6369c2ddd5203b1a4abe352cb4bb43db7a)]
2980
3026
  - chore: husky, lint-staged use fixed versions [valentinab25 - [`f0a8061`](https://github.com/eea/volto-cca-policy/commit/f0a8061c275c236deb00087c23fac9860a073106)]
2981
3027
 
2982
3028
  #### :hammer_and_wrench: Others
@@ -2993,9 +3039,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
2993
3039
  - Refs #259267 - jenkins test [Tripon Eugen - [`cacd31e`](https://github.com/eea/volto-cca-policy/commit/cacd31e7b1afe0983674ed5c7632d2e1d7fa752e)]
2994
3040
  - Refs #259267 - jenkins [Tripon Eugen - [`5b3affe`](https://github.com/eea/volto-cca-policy/commit/5b3affee8401239de10097884c1b7f2349d15ec0)]
2995
3041
  - Refs #259267 - add When, lead image and title to files [Tripon Eugen - [`2cedb23`](https://github.com/eea/volto-cca-policy/commit/2cedb237f898af9057e13fba94b615ef71077204)]
2996
- - test: [JENKINS] Add cpu limit on cypress docker [valentinab25 - [`4d607a5`](https://github.com/eea/volto-cca-policy/commit/4d607a576e9d0a5c34e48c41b409e7df616ee3d6)]
2997
- - test: [JENKINS] Increase shm-size to cypress docker [valentinab25 - [`b7f74d5`](https://github.com/eea/volto-cca-policy/commit/b7f74d53513a6edbfbca5cb6d19687929bb1e5db)]
2998
- - test: [JENKINS] Improve cypress time [valentinab25 - [`db65617`](https://github.com/eea/volto-cca-policy/commit/db656173391f65157098d95d388c25f6429753d8)]
2999
3042
  - Refs #259267 - cca event blocks attachments and check not mandatoty fields [Tripon Eugen - [`3138e5a`](https://github.com/eea/volto-cca-policy/commit/3138e5afb5bfbdbed14e27ed457b16867b7fa414)]
3000
3043
  - Refs #256681 - Fix error in CCA Event view menu. ([React Intl] An id must be provided to format a message.) [GhitaB - [`517eeb8`](https://github.com/eea/volto-cca-policy/commit/517eeb817264a47bbfd6b9b7d22aaf22d44ed224)]
3001
3044
  - Refs #161485 - Fix ECDE name conflict. [GhitaB - [`8bfd99f`](https://github.com/eea/volto-cca-policy/commit/8bfd99ff68bb82a04d1c0ed625fa514fcf46289e)]
@@ -3212,7 +3255,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
3212
3255
 
3213
3256
  #### :house: Internal changes
3214
3257
 
3215
- - chore: [JENKINS] Remove alpha testing version [valentinab25 - [`ad1ced0`](https://github.com/eea/volto-cca-policy/commit/ad1ced0971ba116c13a3b5fcc039172cc915c919)]
3216
3258
 
3217
3259
  #### :hammer_and_wrench: Others
3218
3260
 
@@ -3693,7 +3735,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
3693
3735
  #### :hammer_and_wrench: Others
3694
3736
 
3695
3737
  - Refs #158294 - Update supported languages list. [GhitaB - [`0a4f91f`](https://github.com/eea/volto-cca-policy/commit/0a4f91f39b7edc367bd4c127d6a8f273c7788361)]
3696
- - Add Sonarqube tag using cca-frontend addons list [EEA Jenkins - [`8f1f9ce`](https://github.com/eea/volto-cca-policy/commit/8f1f9ce6c22805670cc0800d3c779b6d619d0f31)]
3697
3738
  ### [0.1.1](https://github.com/eea/volto-cca-policy/compare/0.1.0...0.1.1) - 13 December 2022
3698
3739
 
3699
3740
  #### :hammer_and_wrench: Others
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-cca-policy",
3
- "version": "0.3.84",
3
+ "version": "0.3.86",
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",
@@ -2,7 +2,12 @@ import '@testing-library/jest-dom';
2
2
  import { render, screen, fireEvent } from '@testing-library/react';
3
3
  import ImageGallery from './ImageGallery';
4
4
 
5
- jest.mock('react-slick', () => (props) => <div>React Slick Gallery</div>);
5
+ jest.mock('react-slick', () => {
6
+ const React = require('react');
7
+ return React.forwardRef((props, ref) => (
8
+ <div ref={ref}>React Slick Gallery</div>
9
+ ));
10
+ });
6
11
 
7
12
  const mockItems = [
8
13
  {
@@ -6,34 +6,44 @@ import {
6
6
  AccordionContent,
7
7
  } from 'semantic-ui-react';
8
8
 
9
- const AccordionList = ({ accordions, variation }) => {
10
- const [activeIndex, setActiveIndex] = useState(-1);
9
+ const AccordionList = ({ accordions, variation, multiple = false }) => {
10
+ const [activeIndexes, setActiveIndexes] = useState([]);
11
+
11
12
  const handleAccordionClick = (index) => {
12
- setActiveIndex(activeIndex === index ? -1 : index);
13
+ if (multiple) {
14
+ setActiveIndexes((prev) =>
15
+ prev.includes(index)
16
+ ? prev.filter((i) => i !== index)
17
+ : [...prev, index],
18
+ );
19
+ } else {
20
+ setActiveIndexes((prev) => (prev.includes(index) ? [] : [index]));
21
+ }
13
22
  };
14
23
 
15
24
  return (
16
25
  <Accordion className={variation}>
17
- {accordions.map((accordion, index) => (
18
- <React.Fragment key={index}>
19
- <AccordionTitle
20
- active={activeIndex === index}
21
- onClick={() => handleAccordionClick(index)}
22
- >
23
- <Icon
24
- className={
25
- activeIndex === index
26
- ? 'ri-arrow-up-s-line'
27
- : 'ri-arrow-down-s-line'
28
- }
29
- />
30
- {accordion.title}
31
- </AccordionTitle>
32
- <AccordionContent active={activeIndex === index}>
33
- {accordion.content}
34
- </AccordionContent>
35
- </React.Fragment>
36
- ))}
26
+ {accordions.map((accordion, index) => {
27
+ const isActive = activeIndexes.includes(index);
28
+ return (
29
+ <React.Fragment key={index}>
30
+ <AccordionTitle
31
+ active={isActive}
32
+ onClick={() => handleAccordionClick(index)}
33
+ >
34
+ <Icon
35
+ className={
36
+ isActive ? 'ri-arrow-up-s-line' : 'ri-arrow-down-s-line'
37
+ }
38
+ />
39
+ {accordion.title}
40
+ </AccordionTitle>
41
+ <AccordionContent active={isActive}>
42
+ {accordion.content}
43
+ </AccordionContent>
44
+ </React.Fragment>
45
+ );
46
+ })}
37
47
  </Accordion>
38
48
  );
39
49
  };
@@ -0,0 +1,70 @@
1
+ import '@testing-library/jest-dom';
2
+ import { render, screen } from '@testing-library/react';
3
+ import ItemsSection from './ItemsSection';
4
+ import defaultImage from '@eeacms/volto-cca-policy/../theme/assets/images/image-narrow.svg';
5
+
6
+ jest.mock('@eeacms/volto-cca-policy/utils', () => ({
7
+ normalizeImageFileName: (filename) => filename?.toLowerCase() || '',
8
+ }));
9
+
10
+ describe('ItemsSection', () => {
11
+ it('renders nothing when items is empty or undefined', () => {
12
+ const { container, rerender } = render(<ItemsSection items={[]} />);
13
+ expect(container.firstChild).toBeNull();
14
+
15
+ rerender(<ItemsSection />);
16
+ expect(container.firstChild).toBeNull();
17
+ });
18
+
19
+ it('renders default image when item has no icon', () => {
20
+ const mockItems = [{ Sector: 'Water' }];
21
+ render(<ItemsSection items={mockItems} field="Sector" iconPath="sector" />);
22
+
23
+ const image = screen.getByRole('img');
24
+ expect(image).toHaveAttribute('src', defaultImage);
25
+ expect(screen.getByText('Water')).toBeInTheDocument();
26
+ });
27
+
28
+ it('renders custom image when icon is provided', () => {
29
+ const mockItems = [{ Sector: 'Energy', Icon: 'Solar' }];
30
+ render(<ItemsSection items={mockItems} field="Sector" iconPath="sector" />);
31
+
32
+ const image = screen.getByRole('img');
33
+ expect(image).toHaveAttribute(
34
+ 'src',
35
+ '/en/mission/icons/signatory-reporting/sector/solar/@@images/image',
36
+ );
37
+ expect(screen.getByText('Energy')).toBeInTheDocument();
38
+ });
39
+
40
+ it('applies "column" class when more than 3 items exist', () => {
41
+ const mockItems = [
42
+ { Sector: 'Water' },
43
+ { Sector: 'Energy' },
44
+ { Sector: 'Agriculture' },
45
+ { Sector: 'Transport' },
46
+ ];
47
+
48
+ const { container } = render(
49
+ <ItemsSection items={mockItems} field="Sector" iconPath="sector" />,
50
+ );
51
+
52
+ const group = container.querySelector('.items-group');
53
+ expect(group).toHaveClass('column');
54
+ });
55
+
56
+ it('does not apply "column" class when 3 or fewer items', () => {
57
+ const mockItems = [
58
+ { Sector: 'Water' },
59
+ { Sector: 'Energy' },
60
+ { Sector: 'Agriculture' },
61
+ ];
62
+
63
+ const { container } = render(
64
+ <ItemsSection items={mockItems} field="Sector" iconPath="sector" />,
65
+ );
66
+
67
+ const group = container.querySelector('.items-group');
68
+ expect(group).not.toHaveClass('column');
69
+ });
70
+ });
@@ -0,0 +1,12 @@
1
+ import '@testing-library/jest-dom';
2
+ import { render } from '@testing-library/react';
3
+ import NoDataReported from './NoDataReported';
4
+
5
+ describe('NoDataReported', () => {
6
+ it('renders the provided label inside Tab.Pane', () => {
7
+ const testLabel = 'No data available';
8
+ const { getByText } = render(<NoDataReported label={testLabel} />);
9
+
10
+ expect(getByText(testLabel)).toBeInTheDocument();
11
+ });
12
+ });
@@ -0,0 +1,22 @@
1
+ import '@testing-library/jest-dom';
2
+ import { render } from '@testing-library/react';
3
+ import StatisticSection from './StatisticSection';
4
+
5
+ describe('StatisticSection', () => {
6
+ const mockStatistics = [
7
+ { label: 'Population year', value: 2023 },
8
+ { label: 'Population size', value: 362.133 },
9
+ ];
10
+
11
+ it('renders all statistic values and labels', () => {
12
+ const { getByText } = render(
13
+ <StatisticSection statistic={mockStatistics} />,
14
+ );
15
+
16
+ expect(getByText('2023')).toBeInTheDocument();
17
+ expect(getByText('362.133')).toBeInTheDocument();
18
+
19
+ expect(getByText('Population year')).toBeInTheDocument();
20
+ expect(getByText('Population size')).toBeInTheDocument();
21
+ });
22
+ });
@@ -1,4 +1,3 @@
1
- import { useLocation } from 'react-router-dom';
2
1
  import { Tab, Grid } from 'semantic-ui-react';
3
2
  import { Callout } from '@eeacms/volto-eea-design-system/ui';
4
3
  import { HTMLField } from '@eeacms/volto-cca-policy/helpers';
@@ -8,14 +7,9 @@ import NoDataReported from '../NoDataReported';
8
7
  import ItemsSection from '../ItemsSection';
9
8
 
10
9
  const ActionTabContent = ({ action }) => {
11
- const location = useLocation();
12
10
  const hasHazards = action?.Climate_Hazards?.length > 0;
13
- const hasSectors = action?.Sectors.length > 0;
14
- const hasBenefits = action?.Co_Benefits.length > 0;
15
-
16
- const isSandbox = location.pathname.includes(
17
- '/mission/sandbox/eea-sandbox/signatory-reporting',
18
- );
11
+ const hasSectors = action?.Sectors?.length > 0;
12
+ const hasBenefits = action?.Co_Benefits?.length > 0;
19
13
 
20
14
  return (
21
15
  <>
@@ -34,7 +28,8 @@ const ActionTabContent = ({ action }) => {
34
28
  {hasSectors && (
35
29
  <>
36
30
  <h5 className="small-label">{action.Sectors_Label}</h5>
37
- {isSandbox ? (
31
+
32
+ {action.Sectors.some((s) => s.Icon) ? (
38
33
  <ItemsSection
39
34
  items={action.Sectors}
40
35
  field="Sector"
@@ -65,17 +60,14 @@ const ActionTabContent = ({ action }) => {
65
60
  )}
66
61
  </Grid>
67
62
  {action.Funding_Sources && (
68
- <>
69
- <br />
70
- <div className="funding-sources">
71
- <span>{action.Funding_Sources_Label} </span>
72
- <strong>
73
- <HTMLField
74
- value={{ data: formatTextToHTML(action.Funding_Sources) }}
75
- />
76
- </strong>
77
- </div>
78
- </>
63
+ <div className="funding-sources">
64
+ <span>{action.Funding_Sources_Label} </span>
65
+ <strong>
66
+ <HTMLField
67
+ value={{ data: formatTextToHTML(action.Funding_Sources) }}
68
+ />
69
+ </strong>
70
+ </div>
79
71
  )}
80
72
  </>
81
73
  );
@@ -41,8 +41,9 @@ const AssessmentTab = ({ result, general_text }) => {
41
41
  Hazards_Title,
42
42
  Hazards_Abstract,
43
43
  } = result.assessment_text?.[0] || {};
44
- const assessment_risks = result.assessment_risks || [];
45
- const assessment_hazards_sectors = result.assessment_hazards_sectors || [];
44
+
45
+ const assessment_risks = result?.assessment_risks || [];
46
+ const assessment_hazards_sectors = result?.assessment_hazards_sectors || [];
46
47
  const { No_Data_Reported_Label } = general_text || {};
47
48
 
48
49
  const NoResults =
@@ -58,6 +59,7 @@ const AssessmentTab = ({ result, general_text }) => {
58
59
  return (
59
60
  <Tab.Pane className="assessment-tab">
60
61
  {Title && <h2>{Title}</h2>}
62
+
61
63
  {Subheading && (
62
64
  <Callout>
63
65
  <HTMLField value={{ data: formatTextToHTML(Subheading) }} />
@@ -69,7 +71,7 @@ const AssessmentTab = ({ result, general_text }) => {
69
71
  <div className="tab-section-wrapper assessment">
70
72
  {Cra_Title && <h3>{Cra_Title}</h3>}
71
73
 
72
- {result.assessment_factors.length > 0 && (
74
+ {result.assessment_factors?.length > 0 && (
73
75
  <>
74
76
  {Cra_Abstract && <h5>{Cra_Abstract}</h5>}
75
77
  <ItemsSection
@@ -83,26 +85,19 @@ const AssessmentTab = ({ result, general_text }) => {
83
85
  {assessment_risks.length > 0 && (
84
86
  <>
85
87
  {Attachments && <h4>{Attachments}</h4>}
86
- {assessment_risks.map((risk, index) => {
87
- const title = risk?.Attachment_Title
88
- ? `${risk.Assessment_Id}. ${risk.Attachment_Title} - ${
89
- risk.Year_Of_Publication || ''
90
- }`
91
- : null;
92
- return (
93
- <div key={index}>
94
- <AccordionList
95
- variation="tertiary"
96
- accordions={[
97
- {
98
- title: title,
99
- content: <AssessmentAccordionContent result={risk} />,
100
- },
101
- ]}
102
- />
103
- </div>
104
- );
105
- })}
88
+
89
+ <AccordionList
90
+ variation="tertiary"
91
+ multiple={false}
92
+ accordions={assessment_risks.map((risk, index) => ({
93
+ title: risk?.Attachment_Title
94
+ ? `${index + 1}. ${risk.Attachment_Title} - ${
95
+ risk.Year_Of_Publication || ''
96
+ }`
97
+ : `Risk ${index + 1}`,
98
+ content: <AssessmentAccordionContent result={risk} />,
99
+ }))}
100
+ />
106
101
  </>
107
102
  )}
108
103
  </div>
@@ -115,18 +110,52 @@ const AssessmentTab = ({ result, general_text }) => {
115
110
 
116
111
  <br />
117
112
 
118
- {assessment_hazards_sectors && (
113
+ {assessment_hazards_sectors?.length > 0 && (
119
114
  <AccordionList
120
- accordions={assessment_hazards_sectors.map((category) => ({
121
- title: category.Hazard,
122
- content: (
123
- <ul>
124
- {category.Sectors.map((sector, idx) => (
125
- <li key={idx}>{sector}</li>
126
- ))}
127
- </ul>
128
- ),
129
- }))}
115
+ accordions={assessment_hazards_sectors.flatMap((item) => {
116
+ // Beta data (Category > Hazards > Sectors)
117
+ if (item.Category && Array.isArray(item.Hazards)) {
118
+ return [
119
+ {
120
+ title: item.Category,
121
+ content: (
122
+ <ul>
123
+ {item.Hazards.map((hazard, index) => (
124
+ <li key={index}>
125
+ <strong>{hazard.Hazard}</strong>
126
+ {Array.isArray(hazard.Sectors) &&
127
+ hazard.Sectors.length > 0 && (
128
+ <ul>
129
+ {hazard.Sectors.map((sector, sIndex) => (
130
+ <li key={sIndex}>{sector}</li>
131
+ ))}
132
+ </ul>
133
+ )}
134
+ </li>
135
+ ))}
136
+ </ul>
137
+ ),
138
+ },
139
+ ];
140
+ }
141
+
142
+ // Production data (Category=null but has Hazards array)
143
+ if (item.Category === null && Array.isArray(item.Hazards)) {
144
+ return item.Hazards.map((hazard) => ({
145
+ title: hazard.Hazard,
146
+ content: (
147
+ <ul>
148
+ {Array.isArray(hazard.Sectors) &&
149
+ hazard.Sectors.map((sector, index) => (
150
+ <li key={index}>{sector}</li>
151
+ ))}
152
+ </ul>
153
+ ),
154
+ }));
155
+ }
156
+
157
+ return [];
158
+ })}
130
159
  />
131
160
  )}
132
161
  </Tab.Pane>
@@ -6,6 +6,14 @@ jest.mock('@eeacms/volto-eea-design-system/ui', () => ({
6
6
  Callout: ({ children }) => <div>{children}</div>,
7
7
  }));
8
8
 
9
+ jest.mock('@eeacms/volto-cca-policy/helpers', () => ({
10
+ HTMLField: ({ value }) => <div>{value.data}</div>,
11
+ }));
12
+
13
+ jest.mock('../NoDataReported', () => ({ label }) => (
14
+ <div data-testid="no-data">{label}</div>
15
+ ));
16
+
9
17
  jest.mock('@eeacms/volto-cca-policy/utils', () => ({
10
18
  isEmpty: (arr) => !arr || arr.length === 0,
11
19
  formatTextToHTML: (text) => text,
@@ -38,13 +46,28 @@ const mockData = {
38
46
  Please_Explain: 'Explanation content here.',
39
47
  },
40
48
  ],
49
+ assessment_hazards_sectors: [
50
+ {
51
+ Category: 'Water Management',
52
+ Hazards: [
53
+ { Hazard: 'Flooding', Sectors: ['Agriculture', 'Health'] },
54
+ { Hazard: 'Drought', Sectors: ['Energy'] },
55
+ ],
56
+ },
57
+ {
58
+ Category: null,
59
+ Hazards: [
60
+ { Hazard: 'Storms', Sectors: ['Transport', 'Tourism'] },
61
+ { Hazard: 'Heatwaves', Sectors: ['Health'] },
62
+ ],
63
+ },
64
+ ],
41
65
  };
42
66
 
43
67
  describe('AssessmentTab', () => {
44
- it('renders core sections and nested tabs', () => {
68
+ it('renders all major sections correctly', () => {
45
69
  render(<AssessmentTab result={mockData} />);
46
70
 
47
- // General headings
48
71
  expect(screen.getByText('Assessment Title')).toBeInTheDocument();
49
72
  expect(screen.getByText('Assessment Subheading')).toBeInTheDocument();
50
73
  expect(
@@ -56,8 +79,54 @@ describe('AssessmentTab', () => {
56
79
  expect(screen.getByText('Hazards')).toBeInTheDocument();
57
80
  expect(screen.getByText('Hazards abstract text.')).toBeInTheDocument();
58
81
 
59
- // Items section
60
82
  expect(screen.getByText('Factor A')).toBeInTheDocument();
61
83
  expect(screen.getByText('Factor B')).toBeInTheDocument();
62
84
  });
85
+
86
+ it('renders assessment risks accordion with link and details', () => {
87
+ render(<AssessmentTab result={mockData} />);
88
+
89
+ expect(
90
+ screen.getByText('1. Risk Attachment Title - 2023'),
91
+ ).toBeInTheDocument();
92
+
93
+ expect(screen.getByText('Explore this risk')).toBeInTheDocument();
94
+ expect(screen.getByText('Details')).toBeInTheDocument();
95
+ expect(screen.getByText('Explanation content here.')).toBeInTheDocument();
96
+
97
+ const link = screen.getByRole('link', { name: 'Explore this risk' });
98
+ expect(link).toHaveAttribute('href', 'https://example.com');
99
+ });
100
+
101
+ it('renders beta-style hazards (Category > Hazard > Sector)', () => {
102
+ render(<AssessmentTab result={mockData} />);
103
+
104
+ expect(screen.getByText('Water Management')).toBeInTheDocument();
105
+ expect(screen.getByText('Flooding')).toBeInTheDocument();
106
+ expect(screen.getByText('Drought')).toBeInTheDocument();
107
+
108
+ expect(screen.getByText('Agriculture')).toBeInTheDocument();
109
+ expect(screen.getAllByText('Health').length).toBeGreaterThanOrEqual(1);
110
+ expect(screen.getByText('Energy')).toBeInTheDocument();
111
+ });
112
+
113
+ it('renders production-style hazards (Hazard > Sectors)', () => {
114
+ render(<AssessmentTab result={mockData} />);
115
+
116
+ expect(screen.getByText('Storms')).toBeInTheDocument();
117
+ expect(screen.getByText('Heatwaves')).toBeInTheDocument();
118
+ expect(screen.getByText('Transport')).toBeInTheDocument();
119
+ expect(screen.getByText('Tourism')).toBeInTheDocument();
120
+ expect(screen.getAllByText('Health').length).toBeGreaterThanOrEqual(1);
121
+ });
122
+
123
+ it('renders NoDataReported when no data available', () => {
124
+ render(
125
+ <AssessmentTab
126
+ result={{}}
127
+ general_text={{ No_Data_Reported_Label: 'No info' }}
128
+ />,
129
+ );
130
+ expect(screen.getByTestId('no-data')).toHaveTextContent('No info');
131
+ });
63
132
  });
@@ -63,19 +63,19 @@ const GovernanceTab = ({ result, general_text }) => {
63
63
 
64
64
  {Describe && <HTMLField value={{ data: formatTextToHTML(Describe) }} />}
65
65
 
66
- <br />
67
-
68
66
  {Provide && (
69
- <AccordionList
70
- accordions={[
71
- {
72
- title: Provide_Title,
73
- content: (
74
- <HTMLField value={{ data: formatTextToHTML(Provide) }} />
75
- ),
76
- },
77
- ]}
78
- />
67
+ <div className="provide-section">
68
+ <AccordionList
69
+ accordions={[
70
+ {
71
+ title: Provide_Title,
72
+ content: (
73
+ <HTMLField value={{ data: formatTextToHTML(Provide) }} />
74
+ ),
75
+ },
76
+ ]}
77
+ />
78
+ </div>
79
79
  )}
80
80
  </Tab.Pane>
81
81
  );
@@ -127,9 +127,8 @@ const PlanningTab = ({ result, general_text }) => {
127
127
 
128
128
  {planning_climate_action.map((action, index) => (
129
129
  <React.Fragment key={index}>
130
- <br />
131
130
  {action?.Sectors_Introduction && (
132
- <Message>
131
+ <Message className="sectors-introduction">
133
132
  <HTMLField
134
133
  value={{
135
134
  data: formatTextToHTML(action.Sectors_Introduction),
@@ -160,32 +159,27 @@ const PlanningTab = ({ result, general_text }) => {
160
159
  </p>
161
160
  )}
162
161
 
163
- {action?.Name_Of_Plan_And_Hyperlink && (
164
- <p>
165
- {(() => {
166
- const { name, url } = extractPlanNameAndURL(
167
- action.Name_Of_Plan_And_Hyperlink,
168
- );
169
- return url ? (
170
- <a href={url} title={name} target="_blank" rel="noreferrer">
171
- <strong>
172
- {action.Further_Information_Link_Text}
173
- {name && ` [${name}]`}
174
- </strong>
162
+ {(() => {
163
+ const { url } = extractPlanNameAndURL(
164
+ action?.Name_Of_Plan_And_Hyperlink,
165
+ );
166
+
167
+ if (url && action?.Further_Information_Link_Text) {
168
+ return (
169
+ <p>
170
+ <a href={url} target="_blank" rel="noreferrer">
171
+ <strong>{action.Further_Information_Link_Text}</strong>
175
172
  </a>
176
- ) : (
177
- <strong>
178
- {action.Further_Information_Link_Text}
179
- {name && ` [${name}]`}
180
- </strong>
181
- );
182
- })()}
183
- </p>
184
- )}
173
+ </p>
174
+ );
175
+ }
176
+
177
+ return null;
178
+ })()}
185
179
 
186
180
  {action?.Attachment && (
187
181
  <p>
188
- <a href={action.Attachment}>
182
+ <a href={action.Attachment} target="_blank" rel="noreferrer">
189
183
  <strong>{action.Explore_Plan_Link_Text}</strong>
190
184
  </a>
191
185
  </p>
@@ -105,7 +105,7 @@ describe('PlanningTab', () => {
105
105
  it('renders hyperlink with extracted name and URL', () => {
106
106
  const { getByText } = render(<PlanningTab result={mockResult} />);
107
107
 
108
- const link = getByText(/More Info \[Plan Example\]/);
108
+ const link = getByText('More Info');
109
109
  expect(link).toBeInTheDocument();
110
110
  expect(link.closest('a')).toHaveAttribute('href', 'https://plan-link.com');
111
111
  });
package/src/utils.js CHANGED
@@ -113,24 +113,29 @@ const trimTrailingChars = (str) => {
113
113
  export const extractPlanNameAndURL = (text) => {
114
114
  if (!text) return { name: '', url: '' };
115
115
 
116
- // Match URL inside parentheses
117
- const parenthesisMatch = text.match(/\((https?:\/\/[^\s)]+)\)/);
118
- // Match first direct URL not inside parentheses
119
- const directMatch = text.match(/https?:\/\/[^\s,;)]+/);
120
- const url = parenthesisMatch?.[1] || directMatch?.[0] || '';
116
+ // Match all URLs
117
+ const urls = text.match(/https?:\/\/[^\s,;)]+/g) || [];
121
118
 
122
119
  let name = text;
120
+ let url = '';
123
121
 
124
- if (url) {
125
- // Remove URL and any punctuation before it
126
- name = name.replace(`(${url})`, '').replace(url, '');
127
- name = trimTrailingChars(name).trim();
122
+ if (urls.length > 1) {
123
+ // Edge case like Rotterdam: use second URL as the actual link
124
+ name = text.split(urls[0])[0] || urls[0]; // name is before or equals first URL
125
+ url = urls[1];
126
+ } else {
127
+ const parenthesisMatch = text.match(/\((https?:\/\/[^\s)]+)\)/);
128
+ const directMatch = text.match(/https?:\/\/[^\s,;)]+/);
129
+ url = parenthesisMatch?.[1] || directMatch?.[0] || '';
130
+
131
+ if (url) {
132
+ name = text.replace(`(${url})`, '').replace(url, '');
133
+ }
128
134
  }
129
135
 
130
- return {
131
- name: name,
132
- url,
133
- };
136
+ name = trimTrailingChars(name).trim();
137
+
138
+ return { name, url };
134
139
  };
135
140
 
136
141
  export const isEmpty = (arr) => !Array.isArray(arr) || arr.length === 0;
@@ -112,6 +112,20 @@ body.subsite-mkh {
112
112
  margin: 2em 0;
113
113
  }
114
114
 
115
+ ul > li > ul {
116
+ margin-top: 0.3em;
117
+ margin-bottom: 1em;
118
+ }
119
+
120
+ .sectors-introduction {
121
+ margin-top: 3em;
122
+ }
123
+
124
+ .funding-sources,
125
+ .provide-section {
126
+ margin-top: 1em;
127
+ }
128
+
115
129
  .action-tab {
116
130
  .ui.items.items-group {
117
131
  margin: 1em 0;
@@ -169,6 +183,12 @@ body.subsite-mkh {
169
183
  margin-bottom: 1em;
170
184
  }
171
185
 
186
+ .ui.accordion {
187
+ .content.active {
188
+ padding: 1rem 1rem !important;
189
+ }
190
+ }
191
+
172
192
  .tab-section-wrapper {
173
193
  padding: 1.5em;
174
194
  margin: 2em 0;