Skip to content

Commit 189359b

Browse files
authored
Merge pull request #34 from Uni-of-Exeter/adaptation-icon-filtering
Prototype: Adaptation icon filtering
2 parents 4d1fcba + 85b13ac commit 189359b

25 files changed

+18487
-108
lines changed

client/src/App.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ const App = () => {
169169
<div className="grey-section">
170170
<StaticAdaptations
171171
selectedHazardName={selectedHazardName}
172-
setSelectedHazardName={setSelectedHazardName}
173172
applyCoastalFilter={applyCoastalFilter}
174173
/>
175174
</div>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
.horiz-container-pathway {
2+
display: flex;
3+
flex-direction: row;
4+
overflow-x: auto;
5+
flex-wrap: wrap;
6+
width: 100%;
7+
justify-content: space-around;
8+
}
9+
10+
.vert-container-pathway {
11+
all: unset;
12+
display: flex;
13+
flex-direction: column;
14+
text-align: center;
15+
font-size: 75%;
16+
width: 33.3%;
17+
box-sizing: border-box;
18+
margin-bottom: 1.5em;
19+
line-height: 1.6;
20+
justify-content: space-between;
21+
}
22+
23+
.vert-container-pathway:hover {
24+
background: none;
25+
color: inherit;
26+
border: none;
27+
}
28+
29+
.pathway-text {
30+
padding: 1em;
31+
font-size: 120%;
32+
}
33+
34+
@media (min-width: 1000px) {
35+
.vert-container-pathway {
36+
width: 16.66%;
37+
}
38+
}
39+
40+
@media (max-width: 1000px) {
41+
.horiz-container-pathway {
42+
justify-content: flex-start;
43+
}
44+
}
45+
46+
@media (max-width: 450px) {
47+
.adaptation-theme-select {
48+
max-width: 100%;
49+
width: 100%;
50+
box-sizing: border-box;
51+
font-size: 1em;
52+
}
53+
}
54+
55+
@media (max-width: 600px) {
56+
ul {
57+
padding-left: 1em;
58+
}
59+
}

client/src/components/adaptations/StaticAdaptations.jsx

Lines changed: 89 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,39 +10,68 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
1010
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1111
Common Good Public License Beta 1.0 for more details. */
1212

13+
import "./StaticAdaptations.css";
14+
1315
import React, { useEffect, useState } from "react";
14-
import LoadingOverlay from "react-loading-overlay-ts";
1516

1617
import adaptationData from "../../kumu/parsed/adaptation_data.json";
17-
import { defaultState } from "../../utils/defaultState";
1818
import { pathways } from "../climateImpacts/ClimateImpactSummaryData";
1919
import { adaptationFilters } from "./AdaptationCategories";
2020
import StaticAdaptation from "./StaticAdaptation";
2121

2222
const StaticAdaptations = (props) => {
23-
const { selectedHazardName, setSelectedHazardName, applyCoastalFilter } = props;
23+
const { selectedHazardName, applyCoastalFilter } = props;
2424

25+
// Load filter options
2526
const defaultFilterName = adaptationFilters[0].filterName;
2627
const defaultFilterCategory = adaptationFilters[0].category;
27-
2828
const [filterName, setFilterName] = useState(defaultFilterName);
2929
const [filterCategory, setFilterCategory] = useState(defaultFilterCategory);
30-
const [loading, setLoading] = useState(false);
3130

3231
// Filter pathways if coastal filter is applied
3332
const [filteredPathwayData, setFilteredPathwayData] = useState(pathways);
3433

34+
// Track array of selected hazards (controlled via buttons)
35+
const [selectedHazards, setSelectedHazards] = useState([selectedHazardName]);
36+
37+
// Function for clicking on filter buttons: adding and removing hazards to array
38+
const toggleHazardSelection = (hazardName) => {
39+
setSelectedHazards((prev) => {
40+
// Check to see if new hazardName is selected
41+
const isSelected = prev.includes(hazardName);
42+
43+
// If hazardName is selected, remove it
44+
if (isSelected) {
45+
return prev.filter((n) => n !== hazardName);
46+
}
47+
48+
// If not selected, add it to array
49+
if (!isSelected) {
50+
return [...prev, hazardName];
51+
}
52+
53+
// If selected and the only one do nothing
54+
return prev;
55+
});
56+
};
57+
58+
// When coastal filter is applied, filter pathways and reset selectedHazards
3559
useEffect(() => {
3660
if (applyCoastalFilter) {
3761
setFilteredPathwayData(pathways.filter((pathway) => !pathway.isCoastal));
3862
} else {
3963
setFilteredPathwayData(pathways);
4064
}
41-
setSelectedHazardName(defaultState.selectedHazardName);
42-
}, [applyCoastalFilter, setSelectedHazardName]);
65+
setSelectedHazards([selectedHazardName]);
66+
}, [applyCoastalFilter, selectedHazardName]);
67+
68+
// When a new selectedHazardName is applied, reset the array of hazards
69+
useEffect(() => {
70+
setSelectedHazards([selectedHazardName]);
71+
}, [selectedHazardName]);
4372

44-
// Handle change in filter: set filterName and filterCategory when dropdown is used
45-
const handleFilterChange = (e) => {
73+
// Handle button change: set filterName and filterCategory when dropdown is used
74+
const handleDropdownChange = (e) => {
4675
const selectedFilterName = e.target.value;
4776
const selectedFilter = adaptationFilters.find((filter) => filter.filterName === selectedFilterName);
4877

@@ -52,19 +81,21 @@ const StaticAdaptations = (props) => {
5281
}
5382
};
5483

55-
// Filter adaptations using filterName and filterCategory
84+
// Filter adaptations based on the selectedHazards array and the filterName
5685
const filteredAdaptations = adaptationData.filter((adaptation) => {
57-
const hazardName = selectedHazardName.toLowerCase();
5886
const layers = adaptation.attributes.layer.map((layer) => layer.toLowerCase());
5987
const adaptationCategories = adaptation.attributes[filterCategory] || [];
6088

89+
// First check that the adaptation contains every hazard in the array of selectedHazards
90+
const matchesAllHazards = selectedHazards.every((hazard) =>
91+
layers.some((layer) => layer.includes(hazard.toLowerCase() + " in full")),
92+
);
93+
94+
// Then check if the adaptation category includes the category filter name
6195
if (filterName === defaultFilterName) {
62-
return layers.some((layer) => layer.includes(hazardName + " in full"));
96+
return matchesAllHazards;
6397
} else {
64-
return (
65-
layers.some((layer) => layer.includes(hazardName + " in full")) &&
66-
adaptationCategories.includes(filterName)
67-
);
98+
return matchesAllHazards && adaptationCategories.includes(filterName);
6899
}
69100
});
70101

@@ -73,37 +104,55 @@ const StaticAdaptations = (props) => {
73104
}
74105

75106
return (
76-
<LoadingOverlay active={loading} spinner text={"Loading adaptations"}>
107+
<div>
77108
<h1>Adaptations</h1>
78109
<p>
79110
Based on the expected climate change and resulting impacts in the UK, the following adaptations should
80111
be considered. These adaptations were identified to reduce risk to humans and the environment while
81-
providing co-benefits where possible. Use the dropdown options to view adaptations by climate impact
82-
pathway, adaptation theme, and activity type.
112+
providing co-benefits where possible. Use the icons to filter adaptations by climate impact pathway.
113+
More than one icon can be selected to see the adaptations relevant to multiple pathways.
114+
Further filtering by adaptation theme is also possible.
83115
</p>
84-
<p>
85-
<b className="static-adaptation-emphasis">Selected climate impact pathway: </b>
86-
<select
87-
value={selectedHazardName}
88-
onChange={(e) => {
89-
setSelectedHazardName(e.target.value);
116+
<div className="horiz-container-pathway">
117+
{filteredPathwayData.map((pathway) => (
118+
<button
119+
className="vert-container-pathway"
120+
key={pathway.id}
121+
onClick={() => toggleHazardSelection(pathway.name)}
122+
>
123+
<div className="pathway-text">
124+
<strong>{pathway.name}</strong>
125+
</div>
126+
<div className="icon">
127+
{React.cloneElement(pathway.icon, { selectedHazard: selectedHazards.includes(pathway.name) })}
128+
</div>
129+
</button>
130+
))}
131+
</div>
132+
<div style={{ display: "flex", justifyContent: "center" }}>
133+
<button
134+
onClick={() => setSelectedHazards([])}
135+
style={{
136+
borderRadius: "8px",
137+
padding: "1rem",
138+
cursor: "pointer",
139+
flexDirection: "column",
140+
margin: "1em",
90141
}}
91142
>
92-
{filteredPathwayData.map((pathway) => (
93-
<option value={pathway.name} key={pathway.id}>
94-
{pathway.name}
95-
</option>
96-
))}
97-
</select>
98-
</p>
143+
<div style={{ fontSize: "0.8em" }}>Reset adaptation filters</div>
144+
</button>
145+
</div>
99146
<ul>
147+
{filteredAdaptations.length > 0 && (
148+
<li>
149+
{filteredAdaptations.length} climate adaptation
150+
{filteredAdaptations.length === 1 ? " was" : "s were"} found
151+
</li>
152+
)}
100153
<li>
101-
{filteredAdaptations.length} climate adaptation
102-
{filteredAdaptations.length === 1 ? " was" : "s were"} found
103-
</li>
104-
<li>
105-
These adaptations can be filtered by theme:{" "}
106-
<select value={filterName} onChange={handleFilterChange}>
154+
These adaptations can be filtered further by theme:{" "}
155+
<select value={filterName} className="adaptation-theme-select" onChange={handleDropdownChange}>
107156
{adaptationFilters.map((filter, index) => (
108157
<option value={filter.filterName} key={index}>
109158
{filter.displayName}
@@ -124,15 +173,15 @@ const StaticAdaptations = (props) => {
124173
);
125174
})
126175
) : (
127-
<h3>No adaptations found</h3>
176+
<h3 style={{ textAlign: "center" }}>No adaptations found</h3>
128177
)}
129178
</div>
130179

131180
<p className="note">
132181
Data source: The adaptation data is based on published scientific literature and reports. You can see
133182
the references used by expanding each adaptation.
134183
</p>
135-
</LoadingOverlay>
184+
</div>
136185
);
137186
};
138187

client/src/components/climateHazard/ClimateHazardData.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import WildfiresSvg from "../../images/hazards/Wildfires.jsx";
2020
export const climateHazardsData = [
2121
{
2222
name: "Heatwaves",
23-
icon: <HeatwaveSvg className="hazard-img" />,
23+
icon: <HeatwaveSvg className="icon" />,
2424
details: (
2525
<div>
2626
<p>
@@ -59,7 +59,7 @@ export const climateHazardsData = [
5959
},
6060
{
6161
name: "Wildfires",
62-
icon: <WildfiresSvg className="hazard-img" />,
62+
icon: <WildfiresSvg className="icon" />,
6363
details: (
6464
<div>
6565
<p>
@@ -87,7 +87,7 @@ export const climateHazardsData = [
8787
},
8888
{
8989
name: "Air Quality",
90-
icon: <AirPollutionSvg className="hazard-img" />,
90+
icon: <AirPollutionSvg className="icon" />,
9191
details: (
9292
<div>
9393
<p>Indoor and outdoor air quality in the UK are affected by climate change.</p>
@@ -142,7 +142,7 @@ export const climateHazardsData = [
142142
},
143143
{
144144
name: "Flooding",
145-
icon: <FloodSvg className="hazard-img" />,
145+
icon: <FloodSvg className="icon" />,
146146
details: (
147147
<div>
148148
<p>
@@ -209,7 +209,7 @@ export const climateHazardsData = [
209209
},
210210
{
211211
name: "Coastal Erosion",
212-
icon: <CoastalErosionSvg className="hazard-img" />,
212+
icon: <CoastalErosionSvg className="icon" />,
213213
details: (
214214
<div>
215215
<p>Coastal erosion is increasing across the UK due to several interacting issues:</p>

client/src/components/climateHazard/ClimateHazardRisk.css

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,6 @@
77
justify-content: space-around;
88
}
99

10-
.hazard-img {
11-
display: flex;
12-
flex-direction: row;
13-
align-items: center;
14-
justify-content: center;
15-
}
16-
1710
.vert-container-hazard {
1811
all: unset;
1912
display: flex;

client/src/components/climateHazard/ClimateHazardRisk.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const ClimateHazardRisk = ({ applyCoastalFilter }) => {
4949
<div className="hazard-text">
5050
<strong>{hazard.name}</strong>
5151
</div>
52-
<div className="hazard-img">{React.cloneElement(hazard.icon, { selectedHazard })}</div>
52+
<div className="icon">{React.cloneElement(hazard.icon, { selectedHazard })}</div>
5353
</button>
5454
))}
5555
</div>

client/src/components/climateImpacts/ClimateImpactSummary.css

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@
1616
border-bottom-width: 4px;
1717
}
1818

19-
.impact-img {
20-
display: flex;
21-
flex-direction: row;
22-
align-items: center;
23-
justify-content: center;
24-
}
25-
2619
.vert-container-impact {
2720
display: flex;
2821
flex-direction: column;

client/src/components/climateImpacts/ClimateImpactSummary.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ const ClimateImpactSummary = ({ loading, selectedHazardName, setSelectedHazardNa
7878
<div className="horiz-container-impact">
7979
{filteredImpacts.map((impact) => (
8080
<div className="vert-container-impact" key={impact.id}>
81-
<div className="impact-img">{impact.icon}</div>
81+
<div className="icon">{impact.icon}</div>
8282
<div className="impact-text">{impact.name}</div>
8383
</div>
8484
))}
@@ -100,7 +100,7 @@ const ClimateImpactSummary = ({ loading, selectedHazardName, setSelectedHazardNa
100100
<div className="horiz-container-impact">
101101
{filteredCommunityImpacts.map((impact) => (
102102
<div className="vert-container-impact" key={impact.id}>
103-
<div className="impact-img">{impact.icon}</div>
103+
<div className="icon">{impact.icon}</div>
104104
<div className="impact-text">{impact.name}</div>
105105
</div>
106106
))}

0 commit comments

Comments
 (0)