@eeacms/volto-cca-policy 1.0.2 → 1.0.4

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 (78) hide show
  1. package/CHANGELOG.md +259 -3
  2. package/jest-addon.config.js +4 -2
  3. package/locales/bg/LC_MESSAGES/volto.po +576 -0
  4. package/locales/cs/LC_MESSAGES/volto.po +576 -0
  5. package/locales/da/LC_MESSAGES/volto.po +576 -0
  6. package/locales/de/LC_MESSAGES/volto.po +576 -0
  7. package/locales/el/LC_MESSAGES/volto.po +576 -0
  8. package/locales/en/LC_MESSAGES/volto.po +576 -0
  9. package/locales/es/LC_MESSAGES/volto.po +576 -0
  10. package/locales/et/LC_MESSAGES/volto.po +576 -0
  11. package/locales/fi/LC_MESSAGES/volto.po +576 -0
  12. package/locales/fr/LC_MESSAGES/volto.po +576 -0
  13. package/locales/ga/LC_MESSAGES/volto.po +576 -0
  14. package/locales/hr/LC_MESSAGES/volto.po +576 -0
  15. package/locales/hu/LC_MESSAGES/volto.po +576 -0
  16. package/locales/is/LC_MESSAGES/volto.po +576 -0
  17. package/locales/it/LC_MESSAGES/volto.po +576 -0
  18. package/locales/lt/LC_MESSAGES/volto.po +576 -0
  19. package/locales/lv/LC_MESSAGES/volto.po +576 -0
  20. package/locales/mt/LC_MESSAGES/volto.po +576 -0
  21. package/locales/nl/LC_MESSAGES/volto.po +576 -0
  22. package/locales/nn/LC_MESSAGES/volto.po +576 -0
  23. package/locales/pl/LC_MESSAGES/volto.po +576 -0
  24. package/locales/pt/LC_MESSAGES/volto.po +576 -0
  25. package/locales/ro/LC_MESSAGES/volto.po +576 -0
  26. package/locales/sk/LC_MESSAGES/volto.po +576 -0
  27. package/locales/sl/LC_MESSAGES/volto.po +576 -0
  28. package/locales/sv/LC_MESSAGES/volto.po +576 -0
  29. package/locales/tr/LC_MESSAGES/volto.po +576 -0
  30. package/locales/volto.pot +577 -1
  31. package/package.json +1 -1
  32. package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueCardItem.jsx +224 -0
  33. package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueCardItem.test.jsx +173 -0
  34. package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueContentView.jsx +189 -0
  35. package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueMapView.jsx +272 -0
  36. package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueMapView.test.jsx +160 -0
  37. package/src/components/Search/NavigatorCatalogue/utils.js +157 -0
  38. package/src/components/Search/NavigatorCatalogue/utils.test.js +132 -0
  39. package/src/components/Search/NavigatorGuide/NavigatorGuideContentView.jsx +409 -0
  40. package/src/components/Search/NavigatorGuide/NavigatorGuideLayout.jsx +8 -0
  41. package/src/components/index.js +2 -0
  42. package/src/components/theme/CompareTools/CompareToolsPanel.jsx +151 -0
  43. package/src/components/theme/CompareTools/CompareToolsPanel.test.jsx +96 -0
  44. package/src/components/theme/CompareTools/CompareToolsView.jsx +475 -0
  45. package/src/components/theme/CompareTools/CompareToolsView.test.jsx +110 -0
  46. package/src/components/theme/CompareTools/utils.js +111 -0
  47. package/src/components/theme/CompareTools/utils.test.jsx +217 -0
  48. package/src/components/theme/Views/ExtendedToolView.jsx +201 -201
  49. package/src/components/theme/Views/ExtendedToolView.test.jsx +420 -58
  50. package/src/constants.js +0 -48
  51. package/src/customizations/volto/reducers/breadcrumbs/breadcrumbs.js +1 -1
  52. package/src/helpers/Utils.jsx +29 -0
  53. package/src/helpers/index.js +3 -0
  54. package/src/index.js +28 -2
  55. package/src/search/index.js +6 -0
  56. package/src/search/navigator_catalogue/config.js +89 -0
  57. package/src/search/navigator_catalogue/facets.js +86 -0
  58. package/src/search/navigator_catalogue/views.js +28 -0
  59. package/src/search/navigator_guide/config.js +70 -0
  60. package/src/search/navigator_guide/facets.js +31 -0
  61. package/src/search/navigator_guide/guideSteps.js +93 -0
  62. package/src/slate-styles.less +4 -0
  63. package/src/state.js +1 -0
  64. package/theme/elements/button.overrides +0 -11
  65. package/theme/elements/label.overrides +15 -0
  66. package/theme/globals/blocks.less +3 -2
  67. package/theme/globals/navigator.less +1090 -0
  68. package/theme/globals/site.overrides +5 -0
  69. package/theme/tokens/colors.less +2 -0
  70. package/artifacts/BLOCKS.md +0 -167
  71. package/artifacts/link-integrity-workflow/README.md +0 -76
  72. package/artifacts/link-integrity-workflow/index.md +0 -33
  73. package/artifacts/link-integrity-workflow/link-integrity-block-fields-report.md +0 -132
  74. package/artifacts/link-integrity-workflow/link-integrity-blocks-report.md +0 -52
  75. package/artifacts/link-integrity-workflow/understanding-link-integrity.md +0 -143
  76. package/artifacts/link-integrity-workflow/volto-block-link-analysis.md +0 -63
  77. package/artifacts/link-integrity-workflow/volto-block-link-discovery.md +0 -60
  78. package/artifacts/test-fixes/test-fixes-specification.md +0 -267
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-cca-policy",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
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",
@@ -0,0 +1,224 @@
1
+ import React from 'react';
2
+ import { Checkbox, Icon, Popup } from 'semantic-ui-react';
3
+ import { defineMessages, useIntl } from 'react-intl';
4
+ import ExternalLink from '@eeacms/search/components/Result/ExternalLink';
5
+ import ResultContext from '@eeacms/search/components/Result/ResultContext';
6
+ import {
7
+ getCompareToolTitle,
8
+ getCompareToolUid,
9
+ useCompareTools,
10
+ } from '../../theme/CompareTools/utils';
11
+
12
+ const messages = defineMessages({
13
+ sector: {
14
+ id: 'Sector',
15
+ defaultMessage: 'Sector',
16
+ },
17
+ hazard: {
18
+ id: 'Hazard',
19
+ defaultMessage: 'Hazard',
20
+ },
21
+ cycle: {
22
+ id: 'Cycle',
23
+ defaultMessage: 'Cycle',
24
+ },
25
+ license: {
26
+ id: 'License',
27
+ defaultMessage: 'License',
28
+ },
29
+ type: {
30
+ id: 'Type',
31
+ defaultMessage: 'Type',
32
+ },
33
+ compare: {
34
+ id: 'Compare',
35
+ defaultMessage: 'Compare',
36
+ },
37
+ viewTool: {
38
+ id: 'View tool',
39
+ defaultMessage: 'View tool',
40
+ },
41
+ });
42
+
43
+ const asArray = (value) => {
44
+ if (!value) return [];
45
+ const raw = value.raw !== undefined ? value.raw : value;
46
+ if (!raw) return [];
47
+ return Array.isArray(raw) ? raw.filter(Boolean) : [raw].filter(Boolean);
48
+ };
49
+
50
+ const publicationDateFormatter = new Intl.DateTimeFormat('en-GB', {
51
+ day: '2-digit',
52
+ month: 'short',
53
+ year: '2-digit',
54
+ timeZone: 'UTC',
55
+ });
56
+
57
+ const TagGroup = ({ typeLabel, values, type }) => {
58
+ const visible = values.slice(0, 3);
59
+ const hidden = values.slice(3);
60
+ const remaining = values.length - visible.length;
61
+
62
+ return (
63
+ <div className="navigator-catalogue-tags">
64
+ {visible.map((value) => (
65
+ <span key={`${type}-${value}`} className={`navigator-tag ${type}`}>
66
+ {value}
67
+ </span>
68
+ ))}
69
+ {remaining > 0 && (
70
+ <Popup
71
+ className="catalogue-tag-popup"
72
+ content={
73
+ <div className="catalogue-tag-tooltip">
74
+ <ul>
75
+ {hidden.map((value) => (
76
+ <li key={`${type}-hidden-${value}`}>{value}</li>
77
+ ))}
78
+ </ul>
79
+ </div>
80
+ }
81
+ position="bottom left"
82
+ trigger={
83
+ <button
84
+ type="button"
85
+ className={`navigator-tag ${type} more`}
86
+ aria-label={`${typeLabel}: ${hidden.join(', ')}`}
87
+ >
88
+ + {remaining}
89
+ </button>
90
+ }
91
+ />
92
+ )}
93
+ </div>
94
+ );
95
+ };
96
+
97
+ const CycleElements = ({ intl, values }) => {
98
+ const visible = values.slice(0, 3);
99
+
100
+ if (!visible.length) return null;
101
+
102
+ return (
103
+ <div className="navigator-catalogue-cycle-elements">
104
+ <span className="cycle-elements-label">
105
+ {intl.formatMessage(messages.cycle)}
106
+ </span>
107
+ {visible.map((value, index) => (
108
+ <span
109
+ key={`cycle-element-${index}`}
110
+ className="navigator-tag cycle-element"
111
+ >
112
+ {value}
113
+ </span>
114
+ ))}
115
+ </div>
116
+ );
117
+ };
118
+
119
+ const NavigatorCatalogueCardItem = (props) => {
120
+ const { result } = props;
121
+ const intl = useIntl();
122
+ const sectors = asArray(result.cca_adaptation_sectors);
123
+ const hazards = asArray(result.cca_climate_impacts);
124
+ const licenseStatus = asArray(result.cca_license_status)
125
+ .map((value) => value?.title || value)
126
+ .filter(Boolean)
127
+ .join(', ');
128
+ const toolProvider = result?._result?.tool_provider?.raw;
129
+ const adaptationSupportCycleSteps = asArray(
130
+ result.adaptation_support_cycle_step,
131
+ )
132
+ .map((value) => value?.title?.split(':')[0])
133
+ .filter(Boolean);
134
+ const publicationDate =
135
+ result.publication_date?.raw || result.publication_date;
136
+ const formattedPublicationDate = publicationDate
137
+ ? publicationDateFormatter.format(new Date(publicationDate))
138
+ : '';
139
+ const sectorLabel = intl.formatMessage(messages.sector);
140
+ const hazardLabel = intl.formatMessage(messages.hazard);
141
+ const compareTool = {
142
+ uid: getCompareToolUid(result),
143
+ title: getCompareToolTitle(result),
144
+ href: result.href,
145
+ };
146
+ const { isSelected, isLimitReached, setSelected } =
147
+ useCompareTools(compareTool);
148
+
149
+ const onCompareChange = (event, { checked }) => {
150
+ setSelected(checked);
151
+ };
152
+
153
+ return (
154
+ <div className={`navigator-catalogue-item${isSelected ? ' selected' : ''}`}>
155
+ <div className="navigator-tool-icon large" aria-hidden="true">
156
+ <Icon className="ri-file-line" />
157
+ </div>
158
+
159
+ <div className="catalogue-item-main">
160
+ <div className="catalogue-item-top">
161
+ <div className="navigator-tool-provider" title={toolProvider}>
162
+ {toolProvider}
163
+ </div>
164
+ {formattedPublicationDate && (
165
+ <span className="catalogue-date">{formattedPublicationDate}</span>
166
+ )}
167
+ </div>
168
+ <div className="catalogue-item-heading">
169
+ <h4>
170
+ <ExternalLink href={result.href} title={result.title}>
171
+ {result.title || '[Tool name]'}
172
+ </ExternalLink>
173
+ </h4>
174
+ </div>
175
+
176
+ <p className="catalogue-description">
177
+ <ResultContext {...props} />
178
+ </p>
179
+
180
+ <div className="catalogue-taxonomy">
181
+ <TagGroup typeLabel={sectorLabel} values={sectors} type="sector" />
182
+ <TagGroup typeLabel={hazardLabel} values={hazards} type="hazard" />
183
+ </div>
184
+
185
+ <div className="catalogue-item-footer">
186
+ <div className="catalogue-meta">
187
+ <CycleElements intl={intl} values={adaptationSupportCycleSteps} />
188
+ </div>
189
+
190
+ <div className="catalogue-meta license-type">
191
+ {licenseStatus && (
192
+ <>
193
+ <span className="catalogue-licence" title={licenseStatus}>
194
+ {intl.formatMessage(messages.license)}: {licenseStatus}
195
+ </span>
196
+ <span aria-hidden="true">·</span>
197
+ </>
198
+ )}
199
+ <span className="catalogue-type">
200
+ {intl.formatMessage(messages.type)}: Tool
201
+ </span>
202
+ </div>
203
+
204
+ <div className="catalogue-actions">
205
+ <label className="catalogue-compare">
206
+ <Checkbox
207
+ checked={isSelected}
208
+ disabled={isLimitReached || !compareTool.uid}
209
+ onChange={onCompareChange}
210
+ />
211
+ <span>{intl.formatMessage(messages.compare)}</span>
212
+ </label>
213
+ <ExternalLink href={result.href} className="ui button primary icon">
214
+ {intl.formatMessage(messages.viewTool)}
215
+ <Icon className="ri-arrow-right-line" />
216
+ </ExternalLink>
217
+ </div>
218
+ </div>
219
+ </div>
220
+ </div>
221
+ );
222
+ };
223
+
224
+ export default NavigatorCatalogueCardItem;
@@ -0,0 +1,173 @@
1
+ import React from 'react';
2
+ import '@testing-library/jest-dom';
3
+ import { fireEvent, render, screen } from '@testing-library/react';
4
+ import { IntlProvider } from 'react-intl';
5
+ import NavigatorCatalogueCardItem from './NavigatorCatalogueCardItem';
6
+ import {
7
+ getCompareToolTitle,
8
+ getCompareToolUid,
9
+ useCompareTools,
10
+ } from '../../theme/CompareTools/utils';
11
+
12
+ jest.mock('semantic-ui-react', () => {
13
+ return {
14
+ Checkbox: ({ checked, disabled, onChange }) => (
15
+ <input
16
+ aria-label="compare"
17
+ type="checkbox"
18
+ checked={checked}
19
+ disabled={disabled}
20
+ onChange={(event) => onChange(event, { checked: event.target.checked })}
21
+ />
22
+ ),
23
+ Icon: ({ className }) => <i className={className} />,
24
+ Popup: ({ content, trigger }) => (
25
+ <div>
26
+ {trigger}
27
+ {content}
28
+ </div>
29
+ ),
30
+ };
31
+ });
32
+
33
+ jest.mock('@eeacms/search/components/Result/ExternalLink', () => ({
34
+ __esModule: true,
35
+ default: ({ children, href, title }) => (
36
+ <a href={href} title={title}>
37
+ {children}
38
+ </a>
39
+ ),
40
+ }));
41
+
42
+ jest.mock('@eeacms/search/components/Result/ResultContext', () => ({
43
+ __esModule: true,
44
+ default: () => <span>Tool description</span>,
45
+ }));
46
+
47
+ jest.mock('../../theme/CompareTools/utils', () => ({
48
+ getCompareToolTitle: jest.fn((result) => result.title || ''),
49
+ getCompareToolUid: jest.fn(
50
+ (result) => result.cca_uid?.raw || result.cca_uid || '',
51
+ ),
52
+ useCompareTools: jest.fn(),
53
+ }));
54
+
55
+ const renderCard = (result) =>
56
+ render(
57
+ <IntlProvider locale="en">
58
+ <NavigatorCatalogueCardItem result={result} />
59
+ </IntlProvider>,
60
+ );
61
+
62
+ describe('NavigatorCatalogueCardItem', () => {
63
+ const setSelected = jest.fn();
64
+
65
+ beforeEach(() => {
66
+ jest.clearAllMocks();
67
+ useCompareTools.mockReturnValue({
68
+ isSelected: false,
69
+ isLimitReached: false,
70
+ setSelected,
71
+ });
72
+ });
73
+
74
+ it('renders complete tool metadata and selects the tool for comparison', () => {
75
+ const result = {
76
+ cca_uid: { raw: 'tool-uid' },
77
+ title: 'Climate planning tool',
78
+ href: 'https://example.com/tool',
79
+ publication_date: { raw: '2026-07-24' },
80
+ cca_adaptation_sectors: {
81
+ raw: ['Agriculture', 'Water', 'Health', 'Energy'],
82
+ },
83
+ cca_climate_impacts: {
84
+ raw: ['Drought', 'Flooding', 'Heat', 'Wildfires'],
85
+ },
86
+ cca_license_status: {
87
+ raw: [
88
+ 'Open data with attribution requirements',
89
+ { title: 'Restricted' },
90
+ ],
91
+ },
92
+ adaptation_support_cycle_step: {
93
+ raw: [
94
+ { title: 'Step 1: Preparing the ground' },
95
+ { title: 'Step 2: Assessing risks' },
96
+ { title: 'Step 3: Identifying options' },
97
+ { title: 'Step 4: Assessing options' },
98
+ ],
99
+ },
100
+ _result: {
101
+ tool_provider: { raw: 'A provider with a long official name' },
102
+ },
103
+ };
104
+
105
+ renderCard(result);
106
+
107
+ expect(screen.getByText('Climate planning tool')).toHaveAttribute(
108
+ 'href',
109
+ 'https://example.com/tool',
110
+ );
111
+ expect(
112
+ screen.getByText('A provider with a long official name'),
113
+ ).toHaveAttribute('title', 'A provider with a long official name');
114
+ expect(screen.getByText('24 Jul 26')).toBeInTheDocument();
115
+ expect(screen.getByText('Agriculture')).toBeInTheDocument();
116
+ expect(screen.getByText('Energy')).toBeInTheDocument();
117
+ expect(screen.getByText('Wildfires')).toBeInTheDocument();
118
+ expect(
119
+ screen.getByRole('button', { name: 'Sector: Energy' }),
120
+ ).toBeInTheDocument();
121
+ expect(
122
+ screen.getByRole('button', { name: 'Hazard: Wildfires' }),
123
+ ).toBeInTheDocument();
124
+ expect(screen.getByText('Step 1')).toBeInTheDocument();
125
+ expect(screen.queryByText('Step 4')).not.toBeInTheDocument();
126
+ expect(
127
+ screen.getByTitle('Open data with attribution requirements, Restricted'),
128
+ ).toHaveTextContent(
129
+ 'License: Open data with attribution requirements, Restricted',
130
+ );
131
+ expect(screen.getByText('Type: Tool')).toBeInTheDocument();
132
+
133
+ fireEvent.click(screen.getByLabelText('compare'));
134
+ expect(setSelected).toHaveBeenCalledWith(true);
135
+ expect(getCompareToolUid).toHaveBeenCalledWith(result);
136
+ expect(getCompareToolTitle).toHaveBeenCalledWith(result);
137
+ expect(useCompareTools).toHaveBeenCalledWith({
138
+ uid: 'tool-uid',
139
+ title: 'Climate planning tool',
140
+ href: 'https://example.com/tool',
141
+ });
142
+ });
143
+
144
+ it('renders sparse results and disables comparison without a UID', () => {
145
+ useCompareTools.mockReturnValue({
146
+ isSelected: true,
147
+ isLimitReached: true,
148
+ setSelected,
149
+ });
150
+
151
+ renderCard({ title: '', href: '/tool' });
152
+
153
+ expect(screen.getByText('[Tool name]')).toBeInTheDocument();
154
+ expect(screen.queryByText('License:')).not.toBeInTheDocument();
155
+ expect(screen.getByLabelText('compare')).toBeDisabled();
156
+ expect(screen.getByLabelText('compare')).toBeChecked();
157
+ });
158
+
159
+ it('supports scalar and explicitly empty raw metadata', () => {
160
+ renderCard({
161
+ cca_uid: 'tool-uid',
162
+ title: 'Scalar metadata tool',
163
+ href: '/tool',
164
+ cca_adaptation_sectors: 'Water',
165
+ cca_climate_impacts: { raw: null },
166
+ cca_license_status: { raw: '' },
167
+ adaptation_support_cycle_step: { raw: null },
168
+ });
169
+
170
+ expect(screen.getByText('Water')).toBeInTheDocument();
171
+ expect(screen.queryByText('License:')).not.toBeInTheDocument();
172
+ });
173
+ });
@@ -0,0 +1,189 @@
1
+ import React from 'react';
2
+ import { Sorting } from '@elastic/react-search-ui';
3
+ import { Grid, Icon, Menu } from 'semantic-ui-react';
4
+ import { defineMessages, useIntl } from 'react-intl';
5
+ import { useAtomValue } from 'jotai';
6
+
7
+ import ResultsPerPageSelector from '@eeacms/search/components/ResultsPerPageSelector/ResultsPerPageSelector';
8
+ import Paging from '@eeacms/search/components/Paging/Paging';
9
+ import {
10
+ ActiveFilterList,
11
+ Component,
12
+ DownloadButton,
13
+ DropdownFacetsList,
14
+ SectionTabs,
15
+ SortingDropdownWithLabel,
16
+ } from '@eeacms/search/components';
17
+ import { NoResults } from '@eeacms/search/components/Result/NoResults';
18
+ import { useSearchContext, useViews } from '@eeacms/search/lib/hocs';
19
+ import { loadingFamily } from '@eeacms/search/state';
20
+ import registry from '@eeacms/search/registry';
21
+ import { CompareToolsPanel } from '@eeacms/volto-cca-policy/components';
22
+
23
+ const NAVIGATOR_VIEW_IDS = ['listing', 'map'];
24
+
25
+ const messages = defineMessages({
26
+ 'Title a-z': {
27
+ id: 'Title a-z',
28
+ defaultMessage: 'Title a-z',
29
+ },
30
+ 'Title z-a': {
31
+ id: 'Title z-a',
32
+ defaultMessage: 'Title z-a',
33
+ },
34
+ Newest: {
35
+ id: 'Newest',
36
+ defaultMessage: 'Newest',
37
+ },
38
+ Oldest: {
39
+ id: 'Oldest',
40
+ defaultMessage: 'Oldest',
41
+ },
42
+ Relevance: {
43
+ id: 'Relevance',
44
+ defaultMessage: 'Relevance',
45
+ },
46
+ 'List view': {
47
+ id: 'List view',
48
+ defaultMessage: 'List view',
49
+ },
50
+ 'Map view': {
51
+ id: 'Map view',
52
+ defaultMessage: 'Map view',
53
+ },
54
+ activeFiltersEditMode: {
55
+ id: 'Active filters are always shown in edit mode',
56
+ defaultMessage: 'Active filters are always shown in edit mode',
57
+ },
58
+ });
59
+
60
+ const NavigatorCatalogueContentView = (props) => {
61
+ const { appConfig, children, wasInteracted } = props;
62
+ const { sortOptions, resultViews } = appConfig;
63
+ const views = useViews();
64
+ const searchContext = useSearchContext();
65
+ const intl = useIntl();
66
+
67
+ const { showFilters, showFacets, showClusters, showSorting } = appConfig;
68
+
69
+ const navigatorResultViews = NAVIGATOR_VIEW_IDS.map((id) =>
70
+ resultViews.find((view) => view.id === id),
71
+ ).filter(Boolean);
72
+
73
+ const activeNavigatorViewId = NAVIGATOR_VIEW_IDS.includes(views.activeViewId)
74
+ ? views.activeViewId
75
+ : navigatorResultViews[0]?.id;
76
+
77
+ React.useEffect(() => {
78
+ if (activeNavigatorViewId && views.activeViewId !== activeNavigatorViewId) {
79
+ views.setActiveViewId(activeNavigatorViewId);
80
+ }
81
+ }, [activeNavigatorViewId, views]);
82
+
83
+ const listingViewDef = resultViews.find(
84
+ (view) => view.id === activeNavigatorViewId,
85
+ );
86
+
87
+ const ResultViewComponent =
88
+ registry.resolve[listingViewDef?.factories.view]?.component;
89
+
90
+ const layoutMode =
91
+ activeNavigatorViewId === 'listing' ? 'fixed' : 'fullwidth';
92
+
93
+ const { wasSearched } = searchContext;
94
+
95
+ const loadingAtom = loadingFamily(appConfig.appName);
96
+ const isLoading = useAtomValue(loadingAtom);
97
+
98
+ const showPaging = appConfig.showLandingPage === false ? true : wasInteracted;
99
+
100
+ const sortOptions2 = sortOptions.map((item) => ({
101
+ ...item,
102
+ name: messages[item.name?.id]
103
+ ? intl.formatMessage(messages[item.name.id])
104
+ : item.name,
105
+ }));
106
+
107
+ if (!ResultViewComponent) return null;
108
+
109
+ return (
110
+ <>
111
+ {appConfig.mode === 'edit' && (
112
+ <div>{intl.formatMessage(messages.activeFiltersEditMode)}</div>
113
+ )}
114
+
115
+ {(showFilters || appConfig.mode === 'edit') && <ActiveFilterList />}
116
+
117
+ {showClusters && <SectionTabs />}
118
+
119
+ <div className={`results-layout ${layoutMode}`}>
120
+ <div className="navigator-catalogue-above-results">
121
+ <Menu pointing secondary className="navigator-view-tabs">
122
+ {navigatorResultViews.map((view) => (
123
+ <Menu.Item
124
+ key={view.id}
125
+ active={activeNavigatorViewId === view.id}
126
+ onClick={() => views.setActiveViewId(view.id)}
127
+ >
128
+ {view.icon && <Icon className={view.icon} />}
129
+ {messages[view.title]
130
+ ? intl.formatMessage(messages[view.title])
131
+ : view.title}
132
+ </Menu.Item>
133
+ ))}
134
+ </Menu>
135
+ </div>
136
+
137
+ {(showFacets || showSorting) && (
138
+ <div className="above-results">
139
+ <div className="above-left">
140
+ {showFacets && <DropdownFacetsList />}
141
+ </div>
142
+
143
+ <div className="above-right">
144
+ {showSorting && (
145
+ <>
146
+ <Component factoryName="SecondaryFacetsList" {...props} />
147
+ <Sorting
148
+ label=""
149
+ sortOptions={sortOptions2}
150
+ view={SortingDropdownWithLabel}
151
+ />
152
+ </>
153
+ )}
154
+ </div>
155
+ </div>
156
+ )}
157
+
158
+ {children.length === 0 && !isLoading && wasSearched && <NoResults />}
159
+
160
+ <ResultViewComponent>{children}</ResultViewComponent>
161
+ <CompareToolsPanel appConfig={appConfig} />
162
+
163
+ {children.length > 0 && activeNavigatorViewId !== 'map' && (
164
+ <div className="search-body-footer">
165
+ <Grid columns={2}>
166
+ <Grid.Column>
167
+ <ResultsPerPageSelector />
168
+ </Grid.Column>
169
+ <Grid.Column textAlign="right" />
170
+ </Grid>
171
+
172
+ <Grid centered>
173
+ <Grid.Column textAlign="center">
174
+ <div className="prev-next-paging">
175
+ {!!showPaging && <Paging />}
176
+ </div>
177
+ <div>
178
+ <DownloadButton appConfig={appConfig} />
179
+ </div>
180
+ </Grid.Column>
181
+ </Grid>
182
+ </div>
183
+ )}
184
+ </div>
185
+ </>
186
+ );
187
+ };
188
+
189
+ export default NavigatorCatalogueContentView;