@eeacms/volto-n2k 1.1.2 → 1.1.3
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 +13 -0
- package/package.json +2 -2
- package/src/components/manage/Blocks/ImageText/Edit.jsx +1 -2
- package/src/components/manage/Blocks/SiteHabitatsList/Filters/HabitatsGroups.jsx +49 -0
- package/src/components/manage/Blocks/SiteHabitatsList/Filters/SortBy.jsx +52 -0
- package/src/components/manage/Blocks/SiteHabitatsList/Filters/View.jsx +201 -0
- package/src/components/manage/Blocks/SiteHabitatsList/Filters/index.js +4 -0
- package/src/components/manage/Blocks/SiteHabitatsList/View.jsx +214 -84
- package/src/components/manage/Blocks/SiteHabitatsList/style.less +256 -45
- package/src/components/manage/Blocks/SiteHabitatsList/utils.js +33 -0
- package/src/components/manage/Blocks/SiteHabitatsListOld/View.jsx +106 -0
- package/src/components/manage/Blocks/SiteHabitatsListOld/index.js +17 -0
- package/src/components/manage/Blocks/SiteHabitatsListOld/schema.js +19 -0
- package/src/components/manage/Blocks/SiteHabitatsListOld/style.less +70 -0
- package/src/components/manage/Blocks/SiteProtectedHabitats/View.jsx +11 -9
- package/src/components/manage/Blocks/SiteProtectedSpecies/View.jsx +11 -9
- package/src/components/manage/Blocks/SiteSpeciesList/Filters/SortBy.jsx +1 -1
- package/src/components/manage/Blocks/SiteSpeciesList/Filters/SpeciesGroups.jsx +10 -4
- package/src/components/manage/Blocks/SiteSpeciesList/Filters/View.jsx +1 -0
- package/src/components/manage/Blocks/SiteSpeciesList/style.less +30 -22
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ 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.3](https://github.com/eea/volto-n2k/compare/1.1.2...1.1.3) - 9 January 2025
|
|
8
|
+
|
|
9
|
+
#### :house: Internal changes
|
|
10
|
+
|
|
11
|
+
- style: Automated code fix [eea-jenkins - [`5364109`](https://github.com/eea/volto-n2k/commit/536410947c52c860c6c51ddd73f3d829880cadbe)]
|
|
12
|
+
- style: Automated code fix [eea-jenkins - [`6c96546`](https://github.com/eea/volto-n2k/commit/6c965460c1d7cfd124981b68e8db64e204846a3d)]
|
|
13
|
+
|
|
14
|
+
#### :hammer_and_wrench: Others
|
|
15
|
+
|
|
16
|
+
- fix sonarqube errors [Claudia Ifrim - [`bbd9b7a`](https://github.com/eea/volto-n2k/commit/bbd9b7a0fb6acf40c3edbf5e2a034b7df0e2048b)]
|
|
17
|
+
- comment filters for habitats, fix z-index for filters on species list [Claudia Ifrim - [`44533aa`](https://github.com/eea/volto-n2k/commit/44533aa781b3b374320071b7cab0adbad322ad5b)]
|
|
18
|
+
- fix ImageText editor [Miu Razvan - [`67e6611`](https://github.com/eea/volto-n2k/commit/67e66113d289d5b3984909aee94e6b343fcd69a9)]
|
|
19
|
+
- Make site habitats list work la species list [Miu Razvan - [`498e995`](https://github.com/eea/volto-n2k/commit/498e9955882bba9c2c549ab29dce5b988f36f489)]
|
|
7
20
|
### [1.1.2](https://github.com/eea/volto-n2k/compare/1.1.1...1.1.2) - 11 December 2024
|
|
8
21
|
|
|
9
22
|
#### :hammer_and_wrench: Others
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eeacms/volto-n2k",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "volto-n2k: Volto add-on",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"author": "European Environment Agency: IDM2 A-Team",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"@eeacms/volto-datablocks": "*",
|
|
28
28
|
"@eeacms/volto-openlayers-map": "*",
|
|
29
29
|
"@eeacms/volto-resize-helper": "*",
|
|
30
|
-
"@eeacms/volto-tabs-block": "*",
|
|
31
30
|
"@eeacms/volto-spotlight": "*",
|
|
31
|
+
"@eeacms/volto-tabs-block": "*",
|
|
32
32
|
"d3": "^7.6.1",
|
|
33
33
|
"d3-shape": "^3.1.0",
|
|
34
34
|
"react-lazy-load-image-component": "1.5.1",
|
|
@@ -18,8 +18,7 @@ const Edit = (props) => {
|
|
|
18
18
|
const { data = {}, selected = false } = props;
|
|
19
19
|
const schema = getSchema();
|
|
20
20
|
const value = { children: data.value || [], isVoid: Editor.isVoid };
|
|
21
|
-
const valueUndefined =
|
|
22
|
-
!value.children.length || Editor.string(value, []) === '';
|
|
21
|
+
const valueUndefined = !value.children.length;
|
|
23
22
|
|
|
24
23
|
const handleKeyDown = (e, index, { disableEnter = false } = {}) => {
|
|
25
24
|
if (e.key === 'Enter' && !e.shiftKey && !disableEnter) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Container } from 'semantic-ui-react';
|
|
3
|
+
import cx from 'classnames';
|
|
4
|
+
|
|
5
|
+
const HabitatsGroups = (props) => {
|
|
6
|
+
const [habitatsGroups, setHabitatsGroups] = React.useState([]);
|
|
7
|
+
const {
|
|
8
|
+
provider_data = {},
|
|
9
|
+
activeHabitatsGroup = 'All',
|
|
10
|
+
setActiveHabitatsGroup = () => {},
|
|
11
|
+
} = props;
|
|
12
|
+
|
|
13
|
+
React.useEffect(() => {
|
|
14
|
+
setHabitatsGroups(
|
|
15
|
+
[
|
|
16
|
+
...(provider_data.habitat_group?.length ? ['All'] : []),
|
|
17
|
+
...new Set(provider_data.habitat_group || []),
|
|
18
|
+
].sort((a, b) => {
|
|
19
|
+
if (a === 'All') return -1;
|
|
20
|
+
if (b === 'All') return 1;
|
|
21
|
+
return a.localeCompare(b);
|
|
22
|
+
}),
|
|
23
|
+
);
|
|
24
|
+
/* eslint-disable-next-line */
|
|
25
|
+
}, [JSON.stringify(provider_data)]);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div className="habitats-groups">
|
|
29
|
+
<Container>
|
|
30
|
+
{habitatsGroups.map((species) => (
|
|
31
|
+
<button
|
|
32
|
+
key={`group-filter-${species}`}
|
|
33
|
+
className={cx({
|
|
34
|
+
'habitats-group': true,
|
|
35
|
+
active: activeHabitatsGroup === species,
|
|
36
|
+
})}
|
|
37
|
+
onClick={() => {
|
|
38
|
+
setActiveHabitatsGroup(species);
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
{species}
|
|
42
|
+
</button>
|
|
43
|
+
))}
|
|
44
|
+
</Container>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default HabitatsGroups;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Dropdown } from 'semantic-ui-react';
|
|
3
|
+
import { Icon } from '@plone/volto/components';
|
|
4
|
+
import upSVG from '@plone/volto/icons/up.svg';
|
|
5
|
+
import downSVG from '@plone/volto/icons/down.svg';
|
|
6
|
+
|
|
7
|
+
const antonyms = {
|
|
8
|
+
ASC: 'DESC',
|
|
9
|
+
DESC: 'ASC',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const View = (props) => {
|
|
13
|
+
const { sortBy, setSortBy } = props;
|
|
14
|
+
|
|
15
|
+
const sortByOptions = [
|
|
16
|
+
{ text: 'Name', value: 'scientific_name', key: 'scientific_name' },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Dropdown aria-label="Sort habitats by" text="SORT BY" floating button>
|
|
21
|
+
<Dropdown.Menu>
|
|
22
|
+
{sortByOptions.map((option) => (
|
|
23
|
+
<Dropdown.Item
|
|
24
|
+
key={option.text}
|
|
25
|
+
active={sortBy === option.value}
|
|
26
|
+
onClick={(e, data) => {
|
|
27
|
+
const activePoperty = sortBy[0];
|
|
28
|
+
const activeOrder = sortBy[1];
|
|
29
|
+
const newOrder =
|
|
30
|
+
activePoperty === option.value ? antonyms[activeOrder] : 'ASC';
|
|
31
|
+
setSortBy([option.value, newOrder]);
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
<p>
|
|
35
|
+
{option.text}
|
|
36
|
+
{sortBy[0] === option.value ? (
|
|
37
|
+
<Icon
|
|
38
|
+
name={sortBy[1] === 'ASC' ? upSVG : downSVG}
|
|
39
|
+
size="14px"
|
|
40
|
+
/>
|
|
41
|
+
) : (
|
|
42
|
+
''
|
|
43
|
+
)}
|
|
44
|
+
</p>
|
|
45
|
+
</Dropdown.Item>
|
|
46
|
+
))}
|
|
47
|
+
</Dropdown.Menu>
|
|
48
|
+
</Dropdown>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default View;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Container,
|
|
4
|
+
Dropdown,
|
|
5
|
+
Sidebar,
|
|
6
|
+
Checkbox,
|
|
7
|
+
Label,
|
|
8
|
+
} from 'semantic-ui-react';
|
|
9
|
+
import { Icon } from '@plone/volto/components';
|
|
10
|
+
// import filterSVG from '@plone/volto/icons/filter.svg';
|
|
11
|
+
import clearSVG from '@plone/volto/icons/clear.svg';
|
|
12
|
+
|
|
13
|
+
import HabitatsGroups from './HabitatsGroups';
|
|
14
|
+
import SortBy from './SortBy';
|
|
15
|
+
|
|
16
|
+
import { filtersLabels } from '../utils';
|
|
17
|
+
|
|
18
|
+
const SidebarFilter = (props) => {
|
|
19
|
+
const { activeFilters, filters, filter, index, setActiveFilters } = props;
|
|
20
|
+
return (
|
|
21
|
+
<div className="filter">
|
|
22
|
+
<div className="header">
|
|
23
|
+
<p className="title">
|
|
24
|
+
{filtersLabels[filter].getTitle().toUpperCase()}
|
|
25
|
+
{!index ? (
|
|
26
|
+
<button
|
|
27
|
+
className="reset-button"
|
|
28
|
+
onClick={() => {
|
|
29
|
+
setActiveFilters({});
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
Reset
|
|
33
|
+
</button>
|
|
34
|
+
) : (
|
|
35
|
+
''
|
|
36
|
+
)}
|
|
37
|
+
</p>
|
|
38
|
+
</div>
|
|
39
|
+
{Object.keys(filters[filter]).map((field) => (
|
|
40
|
+
<div key={filtersLabels[filter][field]} className="checkbox-wrapper">
|
|
41
|
+
<Checkbox
|
|
42
|
+
name={filter}
|
|
43
|
+
label={filtersLabels[filter][field]}
|
|
44
|
+
checked={activeFilters[filter]?.includes(field) || false}
|
|
45
|
+
onClick={() => {
|
|
46
|
+
const newActiveFilters = { ...activeFilters };
|
|
47
|
+
if (newActiveFilters[filter]?.includes(field)) {
|
|
48
|
+
newActiveFilters[filter].splice(
|
|
49
|
+
newActiveFilters[filter].indexOf(field),
|
|
50
|
+
1,
|
|
51
|
+
);
|
|
52
|
+
} else {
|
|
53
|
+
newActiveFilters[filter] = [
|
|
54
|
+
...(activeFilters[filter] || []),
|
|
55
|
+
field,
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
if (!newActiveFilters[filter].length) {
|
|
59
|
+
delete newActiveFilters[filter];
|
|
60
|
+
}
|
|
61
|
+
setActiveFilters(newActiveFilters);
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
<p className="count">{filters[filter][field]}</p>
|
|
65
|
+
</div>
|
|
66
|
+
))}
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const View = (props) => {
|
|
72
|
+
const [visible, setVisible] = React.useState(false);
|
|
73
|
+
const [filters, setFilters] = React.useState({});
|
|
74
|
+
const {
|
|
75
|
+
provider_data,
|
|
76
|
+
activeFilters,
|
|
77
|
+
filteredHabitats,
|
|
78
|
+
pagination,
|
|
79
|
+
sortBy,
|
|
80
|
+
habitats,
|
|
81
|
+
setActiveFilters,
|
|
82
|
+
setPagination,
|
|
83
|
+
setSortBy,
|
|
84
|
+
} = props;
|
|
85
|
+
const itemsPerPageOptions = [
|
|
86
|
+
{ key: '10', text: '10', value: 10 },
|
|
87
|
+
{ key: '25', text: '25', value: 25 },
|
|
88
|
+
{ key: '50', text: '50', value: 50 },
|
|
89
|
+
{ key: '100', text: '100', value: 100 },
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
const updateFilters = () => {
|
|
93
|
+
const newFilters = {};
|
|
94
|
+
Object.keys(filtersLabels).forEach((filter) => {
|
|
95
|
+
newFilters[filter] = {};
|
|
96
|
+
for (let key in filtersLabels[filter]) {
|
|
97
|
+
if (key !== 'getTitle') {
|
|
98
|
+
newFilters[filter][key] =
|
|
99
|
+
filteredHabitats.filter((habitats) => {
|
|
100
|
+
return !!habitats.filter((habitat) => habitat[filter] === key)
|
|
101
|
+
.length;
|
|
102
|
+
}).length || 'none';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
setFilters(newFilters);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
React.useEffect(() => {
|
|
110
|
+
if (provider_data && habitats.length) {
|
|
111
|
+
updateFilters();
|
|
112
|
+
}
|
|
113
|
+
/* eslint-disable-next-line */
|
|
114
|
+
}, [filteredHabitats]);
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<div className="habitats-filters">
|
|
118
|
+
<HabitatsGroups {...props} />
|
|
119
|
+
<Container>
|
|
120
|
+
<div className="active-filters">
|
|
121
|
+
{Object.keys(activeFilters).map((filter) =>
|
|
122
|
+
activeFilters[filter].map((field) => (
|
|
123
|
+
<Label
|
|
124
|
+
className="active-filter"
|
|
125
|
+
key={`active-filter-${field}`}
|
|
126
|
+
as="span"
|
|
127
|
+
>
|
|
128
|
+
{filtersLabels[filter][field]}
|
|
129
|
+
<Icon
|
|
130
|
+
name={clearSVG}
|
|
131
|
+
size="18px"
|
|
132
|
+
onClick={() => {
|
|
133
|
+
const newActiveFilters = { ...activeFilters };
|
|
134
|
+
if (newActiveFilters[filter]?.includes(field)) {
|
|
135
|
+
newActiveFilters[filter].splice(
|
|
136
|
+
newActiveFilters[filter].indexOf(field),
|
|
137
|
+
1,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
if (!newActiveFilters[filter].length) {
|
|
141
|
+
delete newActiveFilters[filter];
|
|
142
|
+
}
|
|
143
|
+
setActiveFilters(newActiveFilters);
|
|
144
|
+
}}
|
|
145
|
+
/>
|
|
146
|
+
</Label>
|
|
147
|
+
)),
|
|
148
|
+
)}
|
|
149
|
+
</div>
|
|
150
|
+
<div className="toolbar">
|
|
151
|
+
<SortBy sortBy={sortBy} setSortBy={setSortBy} />
|
|
152
|
+
<Dropdown
|
|
153
|
+
aria-label="Set number of habitats per page"
|
|
154
|
+
placeholder="Items per page"
|
|
155
|
+
value={pagination.itemsPerPage}
|
|
156
|
+
floating
|
|
157
|
+
button
|
|
158
|
+
options={itemsPerPageOptions}
|
|
159
|
+
onChange={(e, data) => {
|
|
160
|
+
setPagination({ ...pagination, itemsPerPage: data.value });
|
|
161
|
+
}}
|
|
162
|
+
/>
|
|
163
|
+
{/* <button aria-label="Set filters" onClick={() => setVisible(!visible)}>
|
|
164
|
+
<Icon name={filterSVG} size="24px" />
|
|
165
|
+
</button> */}
|
|
166
|
+
</div>
|
|
167
|
+
</Container>
|
|
168
|
+
<Sidebar
|
|
169
|
+
as="div"
|
|
170
|
+
className="z-full"
|
|
171
|
+
animation="overlay"
|
|
172
|
+
direction="right"
|
|
173
|
+
onHide={() => setVisible(false)}
|
|
174
|
+
vertical
|
|
175
|
+
visible={visible}
|
|
176
|
+
width="wide"
|
|
177
|
+
>
|
|
178
|
+
<div className="sidebar-header">
|
|
179
|
+
<p className="title">Filters</p>
|
|
180
|
+
<button className="clear-button" onClick={() => setVisible(false)}>
|
|
181
|
+
<Icon name={clearSVG} size="20px" color="#fff" />
|
|
182
|
+
</button>
|
|
183
|
+
</div>
|
|
184
|
+
<div className="filters">
|
|
185
|
+
{Object.keys(filters).map((filter, index) => (
|
|
186
|
+
<SidebarFilter
|
|
187
|
+
key={filter}
|
|
188
|
+
index={index}
|
|
189
|
+
activeFilters={activeFilters}
|
|
190
|
+
filters={filters}
|
|
191
|
+
filter={filter}
|
|
192
|
+
setActiveFilters={setActiveFilters}
|
|
193
|
+
/>
|
|
194
|
+
))}
|
|
195
|
+
</div>
|
|
196
|
+
</Sidebar>
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export default View;
|
|
@@ -1,104 +1,234 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import findIndex from 'lodash/findIndex';
|
|
3
|
-
import { Icon } from '@plone/volto/components';
|
|
4
2
|
import { Link } from 'react-router-dom';
|
|
5
|
-
import
|
|
6
|
-
import { getObjectByIndex } from '@eeacms/volto-n2k/helpers';
|
|
7
|
-
import
|
|
8
|
-
import
|
|
3
|
+
import { Container, Pagination, Grid } from 'semantic-ui-react';
|
|
4
|
+
import { getObjectByIndex, photoPlaceholders } from '@eeacms/volto-n2k/helpers';
|
|
5
|
+
import { Filters } from './Filters';
|
|
6
|
+
// import { getPopulationString, getLabelString } from './utils';
|
|
7
|
+
|
|
9
8
|
import './style.less';
|
|
10
9
|
|
|
10
|
+
const getCurrentPageLength = (pagination, arr) => {
|
|
11
|
+
const totalPages = Math.ceil(pagination.totalItems / pagination.itemsPerPage);
|
|
12
|
+
if (arr.length < pagination.itemsPerPage) return arr.length;
|
|
13
|
+
if (totalPages === pagination.activePage) {
|
|
14
|
+
return arr.length - (pagination.activePage - 1) * pagination.itemsPerPage;
|
|
15
|
+
}
|
|
16
|
+
return pagination.itemsPerPage;
|
|
17
|
+
};
|
|
18
|
+
|
|
11
19
|
const View = (props) => {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
const {
|
|
21
|
+
provider_data = {},
|
|
22
|
+
placeholder = 'This site does not host any protected habitats',
|
|
23
|
+
} = props;
|
|
24
|
+
const dataReady = React.useRef(false);
|
|
25
|
+
const [activeHabitatsGroup, setActiveHabitatsGroup] = React.useState('All');
|
|
26
|
+
const [filters, setFilters] = React.useState({});
|
|
27
|
+
const [habitats, spetHabitats] = React.useState([]);
|
|
28
|
+
const [filteredHabitats, setFilteredHabitats] = React.useState([]);
|
|
29
|
+
const [pagination, setPagination] = React.useState({
|
|
30
|
+
activePage: 1,
|
|
31
|
+
totalItems: 0,
|
|
32
|
+
itemsPerPage: 10,
|
|
33
|
+
});
|
|
34
|
+
const [sortBy, setSortBy] = React.useState(['scientific_name', 'ASC']);
|
|
35
|
+
|
|
36
|
+
const getSortedHabitats = (habitats = []) => {
|
|
37
|
+
const property = sortBy[0];
|
|
38
|
+
const order = sortBy[1];
|
|
39
|
+
|
|
40
|
+
return habitats.sort((a, b) => {
|
|
41
|
+
const a_value = a[0][property];
|
|
42
|
+
const b_value = b[0][property];
|
|
43
|
+
if (a_value < b_value) return order === 'ASC' ? -1 : 1;
|
|
44
|
+
if (a_value > b_value) return order === 'ASC' ? 1 : -1;
|
|
45
|
+
return 0;
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const getfilteredHabitats = (habitats = []) => {
|
|
50
|
+
const activeFilters = {
|
|
51
|
+
...filters,
|
|
52
|
+
...(activeHabitatsGroup !== 'All'
|
|
53
|
+
? { habitat_group: [activeHabitatsGroup] }
|
|
54
|
+
: {}),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const filteredHabitats = habitats.filter((items, index) => {
|
|
58
|
+
let itemsHaveFilter = true;
|
|
59
|
+
Object.keys(activeFilters).forEach((filter) => {
|
|
60
|
+
let habitatHasFilter = false;
|
|
61
|
+
items.forEach((item) => {
|
|
62
|
+
if (activeFilters[filter].includes(item[filter])) {
|
|
63
|
+
habitatHasFilter = true;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
if (!habitatHasFilter) {
|
|
67
|
+
itemsHaveFilter = false;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return itemsHaveFilter;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
setPagination({
|
|
74
|
+
...pagination,
|
|
75
|
+
activePage: 1,
|
|
76
|
+
totalItems: filteredHabitats.length,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return filteredHabitats;
|
|
80
|
+
};
|
|
15
81
|
|
|
16
82
|
React.useEffect(() => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
83
|
+
dataReady.current = false;
|
|
84
|
+
const habitatsIndex = {};
|
|
85
|
+
const newHabitats = [];
|
|
86
|
+
if (provider_data.scientific_name?.length) {
|
|
87
|
+
provider_data.scientific_name.forEach((_, index) => {
|
|
88
|
+
const habitat = getObjectByIndex(provider_data, index);
|
|
89
|
+
if (!(habitatsIndex[habitat.code_2000] >= 0)) {
|
|
90
|
+
habitatsIndex[habitat.code_2000] = index;
|
|
91
|
+
}
|
|
92
|
+
if (!newHabitats[habitatsIndex[habitat.code_2000]]) {
|
|
93
|
+
newHabitats[habitatsIndex[habitat.code_2000]] = [];
|
|
22
94
|
}
|
|
23
|
-
newHabitats[habitat].push(
|
|
95
|
+
newHabitats[habitatsIndex[habitat.code_2000]].push(habitat);
|
|
24
96
|
});
|
|
25
97
|
}
|
|
26
|
-
|
|
98
|
+
spetHabitats(getSortedHabitats(newHabitats.filter((habitats) => habitats)));
|
|
27
99
|
/* eslint-disable-next-line */
|
|
28
100
|
}, [JSON.stringify(provider_data)]);
|
|
29
101
|
|
|
102
|
+
React.useEffect(() => {
|
|
103
|
+
const filteredHabitats = getSortedHabitats(
|
|
104
|
+
getfilteredHabitats([...habitats]),
|
|
105
|
+
);
|
|
106
|
+
setFilteredHabitats(filteredHabitats);
|
|
107
|
+
/* eslint-disable-next-line */
|
|
108
|
+
}, [habitats, sortBy, activeHabitatsGroup, filters]);
|
|
109
|
+
|
|
30
110
|
return (
|
|
31
|
-
<div className="site-habitats-list">
|
|
32
|
-
{
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
<Icon
|
|
50
|
-
name={expanded ? upKeySVG : downKeySVG}
|
|
51
|
-
onClick={(e) => {
|
|
52
|
-
const index = findIndex(
|
|
53
|
-
expandedHabitats,
|
|
54
|
-
(name) => name === habitat,
|
|
55
|
-
);
|
|
56
|
-
if (index === -1) {
|
|
57
|
-
setExpandedHabitats((prevExpandedHabitats) => [
|
|
58
|
-
...prevExpandedHabitats,
|
|
59
|
-
habitat,
|
|
60
|
-
]);
|
|
61
|
-
} else {
|
|
62
|
-
setExpandedHabitats((prevExpandedHabitats) => {
|
|
63
|
-
const newExpandedHabitats = [...prevExpandedHabitats];
|
|
64
|
-
newExpandedHabitats.splice(index, 1);
|
|
65
|
-
return newExpandedHabitats;
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
e.preventDefault();
|
|
69
|
-
e.stopPropagation();
|
|
70
|
-
}}
|
|
71
|
-
color="#8C8C8C"
|
|
72
|
-
size="32px"
|
|
73
|
-
/>
|
|
74
|
-
</div>
|
|
111
|
+
<div className="site-habitats-list full-width">
|
|
112
|
+
{props.mode !== 'edit' && habitats.length ? (
|
|
113
|
+
<Filters
|
|
114
|
+
{...props}
|
|
115
|
+
activeHabitatsGroup={activeHabitatsGroup}
|
|
116
|
+
activeFilters={filters}
|
|
117
|
+
filteredHabitats={filteredHabitats}
|
|
118
|
+
pagination={pagination}
|
|
119
|
+
sortBy={sortBy}
|
|
120
|
+
habitats={habitats}
|
|
121
|
+
setActiveHabitatsGroup={setActiveHabitatsGroup}
|
|
122
|
+
setActiveFilters={setFilters}
|
|
123
|
+
setPagination={setPagination}
|
|
124
|
+
setSortBy={setSortBy}
|
|
125
|
+
/>
|
|
126
|
+
) : (
|
|
127
|
+
''
|
|
128
|
+
)}
|
|
75
129
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
130
|
+
<div className="habitats-list">
|
|
131
|
+
<Container>
|
|
132
|
+
{filteredHabitats.length ? (
|
|
133
|
+
Array.from(
|
|
134
|
+
{
|
|
135
|
+
length: getCurrentPageLength(pagination, filteredHabitats),
|
|
136
|
+
},
|
|
137
|
+
(v, k) =>
|
|
138
|
+
k + (pagination.activePage - 1) * pagination.itemsPerPage,
|
|
139
|
+
).map((index) => {
|
|
140
|
+
const habitatsData = filteredHabitats[index][0];
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<Grid
|
|
144
|
+
className="habitats"
|
|
145
|
+
key={`${index}-${habitatsData.code_2000}`}
|
|
146
|
+
columns="12"
|
|
147
|
+
>
|
|
148
|
+
<Grid.Row>
|
|
149
|
+
<Grid.Column
|
|
150
|
+
mobile={12}
|
|
151
|
+
tablet={3}
|
|
152
|
+
computer={2}
|
|
153
|
+
className="habitats-photo"
|
|
154
|
+
>
|
|
155
|
+
<img
|
|
156
|
+
src={
|
|
157
|
+
habitatsData.picture_url ||
|
|
158
|
+
photoPlaceholders[habitatsData.habitat_group] ||
|
|
159
|
+
photoPlaceholders.Birds
|
|
160
|
+
}
|
|
161
|
+
alt={habitatsData.habitat_group}
|
|
162
|
+
/>
|
|
163
|
+
</Grid.Column>
|
|
164
|
+
<Grid.Column
|
|
165
|
+
mobile={12}
|
|
166
|
+
tablet={9}
|
|
167
|
+
computer={10}
|
|
168
|
+
className="habitats-details"
|
|
169
|
+
>
|
|
170
|
+
<div className="metadata">
|
|
171
|
+
<div className="name">
|
|
172
|
+
<Link
|
|
173
|
+
as="h3"
|
|
174
|
+
to={`/habitats/${habitatsData.code_2000}`}
|
|
175
|
+
>
|
|
176
|
+
{habitatsData.scientific_name
|
|
177
|
+
? habitatsData.scientific_name + ' '
|
|
178
|
+
: ''}
|
|
179
|
+
<span className="code-2000">
|
|
180
|
+
{' '}
|
|
181
|
+
- {habitatsData.code_2000 || 'NA'}
|
|
182
|
+
</span>
|
|
183
|
+
</Link>
|
|
184
|
+
</div>
|
|
185
|
+
{filteredHabitats[index].map((habitat, index) => (
|
|
186
|
+
<p
|
|
187
|
+
className="habitat-data blue"
|
|
188
|
+
style={{ fontSize: '1.2rem' }}
|
|
189
|
+
key={`habitat-${index}-${habitat.code_2000}`}
|
|
190
|
+
>
|
|
191
|
+
Cover: {habitat.coverage_ha.toFixed(2)} ha (
|
|
192
|
+
{(habitat.coverage_ha / 100).toFixed(4)} km²)
|
|
193
|
+
{habitat.habitat_prioriy
|
|
194
|
+
? `; Priority habitat type: ${habitat.habitat_prioriy}`
|
|
195
|
+
: ''}
|
|
196
|
+
</p>
|
|
197
|
+
))}
|
|
198
|
+
</div>
|
|
199
|
+
<div className="footer-metadata">
|
|
200
|
+
<p className="green">
|
|
201
|
+
Appears in {habitatsData.number_sites} sites
|
|
92
202
|
</p>
|
|
93
203
|
</div>
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
204
|
+
</Grid.Column>
|
|
205
|
+
</Grid.Row>
|
|
206
|
+
</Grid>
|
|
207
|
+
);
|
|
208
|
+
})
|
|
209
|
+
) : habitats.length ? (
|
|
210
|
+
<div className="empty">No results</div>
|
|
211
|
+
) : (
|
|
212
|
+
''
|
|
213
|
+
)}
|
|
214
|
+
{!habitats?.length ? <div className="empty">{placeholder}</div> : ''}
|
|
215
|
+
{pagination.totalItems > 0 ? (
|
|
216
|
+
<Pagination
|
|
217
|
+
activePage={pagination.activePage}
|
|
218
|
+
totalPages={Math.ceil(
|
|
219
|
+
pagination.totalItems / pagination.itemsPerPage,
|
|
220
|
+
)}
|
|
221
|
+
onPageChange={(e, data) => {
|
|
222
|
+
setPagination({ ...pagination, activePage: data.activePage });
|
|
223
|
+
}}
|
|
224
|
+
prevItem={null}
|
|
225
|
+
nextItem={null}
|
|
226
|
+
/>
|
|
227
|
+
) : (
|
|
228
|
+
''
|
|
229
|
+
)}
|
|
230
|
+
</Container>
|
|
231
|
+
</div>
|
|
102
232
|
</div>
|
|
103
233
|
);
|
|
104
234
|
};
|