+
Latitude: {savedCoordinates.lat}
- Longitude: {savedCoordinates.lng}
+ Longitude: {savedCoordinates.lng}
Address: {locationDetails.full_address}
- Ecological Region: {locationDetails.ecological_region}
- Ecological District: {locationDetails.ecological_district}
- Soil Order: {locationDetails.soil_name ? soilString : ""}
+ Ecological Region: {locationDetails.ecological_region}{" "}
+
+ Ecological District:{" "}
+ {locationDetails.ecological_district}
+ Soil Order:{" "}
+ {locationDetails.soil_name ? soilString : ""}
- )
+ );
}
- return null
+ return null;
}
-
export default function Map(props) {
return (
@@ -79,5 +79,5 @@ export default function Map(props) {
- )
+ );
}
diff --git a/frontend/src/components/steps/results/PlantList.js b/frontend/src/components/steps/results/PlantList.jsx
similarity index 100%
rename from frontend/src/components/steps/results/PlantList.js
rename to frontend/src/components/steps/results/PlantList.jsx
diff --git a/frontend/src/components/steps/results/ResultsStep.js b/frontend/src/components/steps/results/ResultsStep.jsx
similarity index 100%
rename from frontend/src/components/steps/results/ResultsStep.js
rename to frontend/src/components/steps/results/ResultsStep.jsx
diff --git a/frontend/src/components/steps/soilvariant/SoilSelector.js b/frontend/src/components/steps/soilvariant/SoilSelector.js
deleted file mode 100644
index 378bde3..0000000
--- a/frontend/src/components/steps/soilvariant/SoilSelector.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import * as React from 'react';
-import Radio from '@mui/material/Radio';
-import RadioGroup from '@mui/material/RadioGroup';
-import FormControlLabel from '@mui/material/FormControlLabel';
-import FormLabel from '@mui/material/FormLabel';
-import FormControl from '@mui/material/FormControl';
-import FormHelperText from '@mui/material/FormHelperText';
-import Tooltip from '@mui/material/Tooltip';
-import staticText from '../../../assets/data/staticText.json'
-
-const WET_SOIL_DESCRIPTION = (
- Is your ground/soil VERY WET? i.e. is it soft and squishy under foot with ground water at or near surface for three months of year or more? Your soil is considered wet if the subsoil is either very dark brown and peat-like, or grey rather than a red, brown, or yellow rusty colour?
-
);
-
-const DRY_SOIL_DESCRIPTION = (
- Is your ground/soil VERY DRY? i.e. If your soil is very well drained, stony, sandy or shallow (less than one metre depth to bed rock, stones or other hard/artificial surface), or is it completely dry for three months of year or more, and not irrigated then we consider it dry.
-
);
-
-const MESIC_SOIL_DESCRIPTION = (
- If your ground/soil does not meet either of the two previous definitions, we’d likely classify it as MOIST, or somewhere in between very wet and very dry. Your ground is considered moist if it has compacted soil that is fine or has a soft/crumbly texture. The sand, silt and clay mixture known as loam is considered moist in this context. Moist soils are more than one metre above an impervious layer, and are never water-logged nor are they completely dry for more than three months. If you are unsure, or if you plan to irrigate your site, then select this option.
-
);
-
-export default function SoilSelector(props) {
- const [value, setValue] = React.useState(props.filters.soilVariant);
- const [helperText, setHelperText] = React.useState(staticText.steps.soil.optionsHelperText);
-
- React.useEffect(() => {
- if (props.filters.soilVariant) {
- props.setNextDisabled(false);
- }
- });
-
- const handleRadioChange = (event) => {
- const soilVariantSelection = event.target.value;
- setValue(soilVariantSelection);
- setHelperText(' ');
- props.updateFilterState({ "soilVariant": soilVariantSelection });
- props.setNextDisabled(false);
- };
-
- return (
-
- );
-}
diff --git a/frontend/src/components/steps/soilvariant/SoilSelector.jsx b/frontend/src/components/steps/soilvariant/SoilSelector.jsx
new file mode 100644
index 0000000..a0a0fac
--- /dev/null
+++ b/frontend/src/components/steps/soilvariant/SoilSelector.jsx
@@ -0,0 +1,111 @@
+import * as React from "react";
+import Radio from "@mui/material/Radio";
+import RadioGroup from "@mui/material/RadioGroup";
+import FormControlLabel from "@mui/material/FormControlLabel";
+import FormLabel from "@mui/material/FormLabel";
+import FormControl from "@mui/material/FormControl";
+import FormHelperText from "@mui/material/FormHelperText";
+import Tooltip from "@mui/material/Tooltip";
+import staticText from "../../../assets/data/staticText.json";
+
+const WET_SOIL_DESCRIPTION = (
+
+ Is your ground/soil VERY WET? i.e. is it soft and squishy
+ under foot with ground water at or near surface for three months of year or
+ more? Your soil is considered wet if the{" "}
+
+ subsoil
+ {" "}
+ is either very dark brown and{" "}
+
+ peat
+
+ -like, or grey rather than a red, brown, or yellow rusty colour?
+
+);
+
+const DRY_SOIL_DESCRIPTION = (
+
+ Is your ground/soil VERY DRY? i.e. If your soil is very
+ well drained, stony, sandy or shallow (less than one metre depth to bed
+ rock, stones or other hard/artificial surface), or is it completely dry for
+ three months of year or more, and not irrigated then we consider it dry.
+
+);
+
+const MESIC_SOIL_DESCRIPTION = (
+
+ If your ground/soil does not meet either of the two previous definitions,
+ we’d likely classify it as{" "}
+ MOIST, or somewhere in between very wet and very dry. Your
+ ground is considered moist if it has compacted soil that is fine or has a
+ soft/crumbly texture. The sand, silt and clay mixture known as loam is
+ considered moist in this context. Moist soils are more than one metre above
+ an impervious layer, and are never water-logged nor are they completely dry
+ for more than three months. If you are unsure, or if you plan to irrigate
+ your site, then select this option.
+
+);
+
+export default function SoilSelector(props) {
+ const [value, setValue] = React.useState(props.filters.soilVariant);
+ const [helperText, setHelperText] = React.useState(
+ staticText.steps.soil.optionsHelperText
+ );
+
+ React.useEffect(() => {
+ if (props.filters.soilVariant) {
+ props.setNextDisabled(false);
+ }
+ });
+
+ const handleRadioChange = (event) => {
+ const soilVariantSelection = event.target.value;
+ setValue(soilVariantSelection);
+ setHelperText(" ");
+ props.updateFilterState({ soilVariant: soilVariantSelection });
+ props.setNextDisabled(false);
+ };
+
+ return (
+
+ );
+}
diff --git a/frontend/src/components/steps/soilvariant/SoilStep.js b/frontend/src/components/steps/soilvariant/SoilStep.js
deleted file mode 100644
index b152a29..0000000
--- a/frontend/src/components/steps/soilvariant/SoilStep.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import Step from '../Step';
-import SoilSelector from './SoilSelector';
-import StepInformation from '../StepInformation';
-import staticText from '../../../assets/data/staticText.json'
-import soilBackgroundImage from '../../../assets/img/stepBackgrounds/step2.jpg';
-
-export default function SoilVariantStep(props) {
- const SOIL_DESCRIPTION = (
- From your site location, we use New Zealand Soil Classification data and additional Manaaki Whenua Landcare Research data to determine overall soil type. However we also need to know as much as possible about the moisture content of the soil at your planting site location.
-
- Please select an option from the choices listed to the right:
-
)
-
- const soilVarientInfoPanel = (
-
- )
-
- const soilVarientSelectionPanel = (
-
-
-
- )
-
- return (
-
- )
-}
diff --git a/frontend/src/components/steps/soilvariant/SoilStep.jsx b/frontend/src/components/steps/soilvariant/SoilStep.jsx
new file mode 100644
index 0000000..bd087c5
--- /dev/null
+++ b/frontend/src/components/steps/soilvariant/SoilStep.jsx
@@ -0,0 +1,50 @@
+import Step from "../Step";
+import SoilSelector from "./SoilSelector";
+import StepInformation from "../StepInformation";
+import staticText from "../../../assets/data/staticText.json";
+import soilBackgroundImage from "../../../assets/img/stepBackgrounds/step2.jpg";
+
+export default function SoilVariantStep(props) {
+ const SOIL_DESCRIPTION = (
+
+ From your site location, we use{" "}
+
+ New Zealand Soil Classification
+ {" "}
+ data and additional{" "}
+
+ Manaaki Whenua Landcare Research
+ {" "}
+ data to determine overall soil type. However we also need to know as much
+ as possible about the moisture content of the soil at your planting site
+ location.
+
+
+ Please select an option from the choices listed to the right:
+
+ );
+
+ const soilVarientInfoPanel = (
+
+ );
+
+ const soilVarientSelectionPanel = (
+
+
+
+ );
+
+ return (
+
+ );
+}
diff --git a/frontend/src/components/steps/specifics/ProjectSpecificsSelector.js b/frontend/src/components/steps/specifics/ProjectSpecificsSelector.js
deleted file mode 100644
index 8ce008b..0000000
--- a/frontend/src/components/steps/specifics/ProjectSpecificsSelector.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { useEffect } from 'react';
-
-export default function ProjectSpecificsSelector(props) {
-
- useEffect(() => {
- props.setNextDisabled(false);
- });
-
- return (
-
Project Specifics Selector
- )
-}
diff --git a/frontend/src/components/steps/specifics/ProjectSpecificsSelector.jsx b/frontend/src/components/steps/specifics/ProjectSpecificsSelector.jsx
new file mode 100644
index 0000000..0b16c56
--- /dev/null
+++ b/frontend/src/components/steps/specifics/ProjectSpecificsSelector.jsx
@@ -0,0 +1,9 @@
+import { useEffect } from "react";
+
+export default function ProjectSpecificsSelector(props) {
+ useEffect(() => {
+ props.setNextDisabled(false);
+ });
+
+ return
Project Specifics Selector
;
+}
diff --git a/frontend/src/components/steps/specifics/ProjectSpecificsStep.js b/frontend/src/components/steps/specifics/ProjectSpecificsStep.js
deleted file mode 100644
index 9bfc6b9..0000000
--- a/frontend/src/components/steps/specifics/ProjectSpecificsStep.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import Step from '../Step';
-import ProjectSpecificsSelector from './ProjectSpecificsSelector'
-import StepInformation from '../StepInformation';
-import staticText from '../../../assets/data/staticText.json'
-
-export default function ProjectSpecificsStep(props) {
- const projectSpecificsInfoPanel = (
-
{staticText.steps.projectSpecifics.description}}
- />
- )
-
- const projectSpecificsSelectionPanel = (
-
- )
-
- return (
-
- )
-}
diff --git a/frontend/src/components/steps/specifics/ProjectSpecificsStep.jsx b/frontend/src/components/steps/specifics/ProjectSpecificsStep.jsx
new file mode 100644
index 0000000..22e0da9
--- /dev/null
+++ b/frontend/src/components/steps/specifics/ProjectSpecificsStep.jsx
@@ -0,0 +1,24 @@
+import Step from "../Step";
+import ProjectSpecificsSelector from "./ProjectSpecificsSelector";
+import StepInformation from "../StepInformation";
+import staticText from "../../../assets/data/staticText.json";
+
+export default function ProjectSpecificsStep(props) {
+ const projectSpecificsInfoPanel = (
+ {staticText.steps.projectSpecifics.description}}
+ />
+ );
+
+ const projectSpecificsSelectionPanel = (
+
+ );
+
+ return (
+
+ );
+}
diff --git a/frontend/src/components/steps/summary/SummaryContent.js b/frontend/src/components/steps/summary/SummaryContent.js
deleted file mode 100644
index c0f28ec..0000000
--- a/frontend/src/components/steps/summary/SummaryContent.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import * as React from 'react';
-import Accordion from '@mui/material/Accordion';
-import AccordionSummary from '@mui/material/AccordionSummary';
-import AccordionDetails from '@mui/material/AccordionDetails';
-import Typography from '@mui/material/Typography';
-import Box from '@mui/material/Box';
-import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
-
-import SummaryTable from './SummaryTable'
-import LocationRepository from '../../../repository/LocationRepository'
-
-
-export default function SummaryContent(props) {
- const [expanded, setExpanded] = React.useState(null);
- const [locationDetails, setLocationDetails] = React.useState({})
-
- const getLocationDetails = () => {
- LocationRepository.getLocationData(props.filters).then(result => {
- setLocationDetails(result);
- })
- }
-
- const handleChange = (panel) => (event, isExpanded) => {
- setExpanded(isExpanded ? panel : false);
- };
-
- React.useEffect(() => {
- props.setNextDisabled(false);
- !Object.keys(locationDetails).length && getLocationDetails()
- });
-
- function createData(name, value) {
- return { name, value };
- }
-
- const locationData = [
- createData('Geographical Coordinates (latitude, longitude)', `(${props.filters.coordinates.lat}, ${props.filters.coordinates.lng})`),
- createData('Ecological Region', locationDetails.ecological_region || ''),
- createData('Ecological District', locationDetails.ecological_district || ''),
- createData('Property Name', locationDetails.full_address || ''),
- ];
-
- const soilData = [
- createData('Soil Order', `${locationDetails.soil_name} (${locationDetails.soil_code})` || ''),
- createData('Soil Variant', props.filters.soilVariant)
- ];
-
- const siteData = [
- createData('Habitat', props.filters.habitat.name ?? ""),
- createData('Zone Name', (props.filters.zone && props.filters.zone.name) ?? ""),
- createData('Zone Variant', (props.filters.zone && props.filters.zone.variant) ?? ""),
- createData('Zone Refined Variant', (props.filters.zone && props.filters.zone.refined_variant) ?? "")
- ];
-
- const regionInformation = () => {
- if (locationDetails.in_chch) {
- return Your location falls within the ecosystem type covered by the Christchurch Council ecosystem maps - further information can be obtained from Ōtautahi/Christchurch ecosystems map.
- } else if (locationDetails.in_auckland) {
- return "Your location falls within the ecosystem type covered by the Auckland Council Tiaki Tāmaki Makaurau Conservation map - further information can be obtained from tiaki Tāmaki Makaurau conservation Auckland
- }
- }
-
- return (
-
-
Please review your choices presented below:
-
- }
- >
- 1. Location Data
-
-
-
-
- {regionInformation()}
-
-
-
-
- }
- >
- 2. Soil Properties
-
-
-
-
-
-
- }
- >
- 3. Project Site Details
-
-
-
-
-
-
- )
-}
diff --git a/frontend/src/components/steps/summary/SummaryContent.jsx b/frontend/src/components/steps/summary/SummaryContent.jsx
new file mode 100644
index 0000000..a50d1a8
--- /dev/null
+++ b/frontend/src/components/steps/summary/SummaryContent.jsx
@@ -0,0 +1,148 @@
+import * as React from "react";
+import Accordion from "@mui/material/Accordion";
+import AccordionSummary from "@mui/material/AccordionSummary";
+import AccordionDetails from "@mui/material/AccordionDetails";
+import Typography from "@mui/material/Typography";
+import Box from "@mui/material/Box";
+import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
+
+import SummaryTable from "./SummaryTable";
+import LocationRepository from "../../../repository/LocationRepository";
+
+export default function SummaryContent(props) {
+ const [expanded, setExpanded] = React.useState(null);
+ const [locationDetails, setLocationDetails] = React.useState({});
+
+ const getLocationDetails = () => {
+ LocationRepository.getLocationData(props.filters).then((result) => {
+ setLocationDetails(result);
+ });
+ };
+
+ const handleChange = (panel) => (event, isExpanded) => {
+ setExpanded(isExpanded ? panel : false);
+ };
+
+ React.useEffect(() => {
+ props.setNextDisabled(false);
+ !Object.keys(locationDetails).length && getLocationDetails();
+ });
+
+ function createData(name, value) {
+ return { name, value };
+ }
+
+ const locationData = [
+ createData(
+ "Geographical Coordinates (latitude, longitude)",
+ `(${props.filters.coordinates.lat}, ${props.filters.coordinates.lng})`
+ ),
+ createData("Ecological Region", locationDetails.ecological_region || ""),
+ createData(
+ "Ecological District",
+ locationDetails.ecological_district || ""
+ ),
+ createData("Property Name", locationDetails.full_address || ""),
+ ];
+
+ const soilData = [
+ createData(
+ "Soil Order",
+ `${locationDetails.soil_name} (${locationDetails.soil_code})` || ""
+ ),
+ createData("Soil Variant", props.filters.soilVariant),
+ ];
+
+ const siteData = [
+ createData("Habitat", props.filters.habitat.name ?? ""),
+ createData(
+ "Zone Name",
+ (props.filters.zone && props.filters.zone.name) ?? ""
+ ),
+ createData(
+ "Zone Variant",
+ (props.filters.zone && props.filters.zone.variant) ?? ""
+ ),
+ createData(
+ "Zone Refined Variant",
+ (props.filters.zone && props.filters.zone.refined_variant) ?? ""
+ ),
+ ];
+
+ const regionInformation = () => {
+ if (locationDetails.in_chch) {
+ return (
+
+ Your location falls within the ecosystem type covered by the
+ Christchurch Council ecosystem maps - further information can be
+ obtained from{" "}
+
+ Ōtautahi/Christchurch ecosystems map
+
+ .
+
+ );
+ } else if (locationDetails.in_auckland) {
+ return (
+
+ "Your location falls within the ecosystem type covered by the Auckland
+ Council Tiaki Tāmaki Makaurau Conservation map - further information
+ can be obtained from{" "}
+
+ tiaki Tāmaki Makaurau conservation Auckland
+
+
+ );
+ }
+ };
+
+ return (
+
+
+ Please review your choices presented below:{" "}
+
+
+ }>
+ 1. Location Data
+
+
+
+
+ {regionInformation()}
+
+
+
+
+ }>
+ 2. Soil Properties
+
+
+
+
+
+
+ }>
+ 3. Project Site Details
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/steps/summary/SummaryStep.js b/frontend/src/components/steps/summary/SummaryStep.js
deleted file mode 100644
index ddc38e2..0000000
--- a/frontend/src/components/steps/summary/SummaryStep.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import Step from '../Step';
-import SummaryContent from './SummaryContent'
-import StepInformation from '../StepInformation';
-import staticText from '../../../assets/data/staticText.json'
-import summaryBackgroundImage from '../../../assets/img/stepBackgrounds/step5.jpg';
-
-export default function SummaryStep(props) {
- const summaryInfoPanel = (
- {staticText.steps.summary.description}}
- />
- )
-
- const summaryContent = (
-
- )
-
- return (
-
- )
-}
diff --git a/frontend/src/components/steps/summary/SummaryStep.jsx b/frontend/src/components/steps/summary/SummaryStep.jsx
new file mode 100644
index 0000000..ef7aa02
--- /dev/null
+++ b/frontend/src/components/steps/summary/SummaryStep.jsx
@@ -0,0 +1,24 @@
+import Step from "../Step";
+import SummaryContent from "./SummaryContent";
+import StepInformation from "../StepInformation";
+import staticText from "../../../assets/data/staticText.json";
+import summaryBackgroundImage from "../../../assets/img/stepBackgrounds/step5.jpg";
+
+export default function SummaryStep(props) {
+ const summaryInfoPanel = (
+ {staticText.steps.summary.description}}
+ />
+ );
+
+ const summaryContent = ;
+
+ return (
+
+ );
+}
diff --git a/frontend/src/components/steps/summary/SummaryTable.js b/frontend/src/components/steps/summary/SummaryTable.jsx
similarity index 59%
rename from frontend/src/components/steps/summary/SummaryTable.js
rename to frontend/src/components/steps/summary/SummaryTable.jsx
index 8342d4a..f921c87 100644
--- a/frontend/src/components/steps/summary/SummaryTable.js
+++ b/frontend/src/components/steps/summary/SummaryTable.jsx
@@ -1,19 +1,19 @@
-import * as React from 'react';
-import Table from '@mui/material/Table';
-import TableBody from '@mui/material/TableBody';
-import TableCell from '@mui/material/TableCell';
-import TableContainer from '@mui/material/TableContainer';
-import TableRow from '@mui/material/TableRow';
+import * as React from "react";
+import Table from "@mui/material/Table";
+import TableBody from "@mui/material/TableBody";
+import TableCell from "@mui/material/TableCell";
+import TableContainer from "@mui/material/TableContainer";
+import TableRow from "@mui/material/TableRow";
export default function BasicTable(props) {
return (
-
+
{props.rows.map((row) => (
{row.name}
diff --git a/frontend/src/components/steps/zone/ZoneSelector.js b/frontend/src/components/steps/zone/ZoneSelector.js
deleted file mode 100644
index aae3e2d..0000000
--- a/frontend/src/components/steps/zone/ZoneSelector.js
+++ /dev/null
@@ -1,117 +0,0 @@
-import { useEffect, useState } from 'react';
-import SiteRepository from '../../../repository/SiteRepository';
-import { HabitatSVG } from '../HabitatSVG'
-
-export default function ZoneSelector(props) {
-
- const [habitatImageObject, setHabitatImageObject] = useState({});
- const [segmentMapping, setSegmentMapping] = useState({});
- const [selectedZoneSegment, setZoneSegment] = useState(null);
-
-
- const setZoneOrRedirect = (zone) => {
- const redirectHabitat = zone && zone.redirect_habitat;
-
- // If there is a redirect habitat set then redirect otherwise set the zone as state
- const newFilterState = redirectHabitat ? { "habitat": { "id": redirectHabitat.id, "name": redirectHabitat.name } } : { "zone": zone };
-
- props.updateFilterState(newFilterState);
- props.setRedirectBack(Boolean(redirectHabitat));
-
- props.setNextDisabled(false);
- }
-
-
- useEffect(() => {
- const getHabitatImage = () => {
- SiteRepository.getHabitatImage(props.filters.habitatImage).then(response => {
- if (response.status === 200) {
- const imageData = response.data
- setHabitatImageObject(imageData)
- }
- })
- }
-
- const setInitialZone = () => {
- if (props.filters.zone) {
- const zone = props.filters.zone
- const zoneSegment = document.querySelectorAll(`.zone-selector-svg svg path[inkscapelabel="${zone.related_svg_segment}"]`)[0];
-
- // If the previously selected zone segment is located in the diagram then highlight it
- if (zoneSegment) {
- setZoneSegment(zoneSegment)
- zoneSegment.style.fill = "#eeeeee"
- zoneSegment.style['fill-opacity'] = 0.5;
- props.setNextDisabled(false);
- }
- }
- }
-
- const getZones = () => {
- SiteRepository.getZones().then(response => {
- if (response.status === 200) {
- const zoneData = response.data
- let newSegmentMapping = {}
- zoneData.forEach(zone => {
- newSegmentMapping[zone.related_svg_segment] = zone
- });
- setSegmentMapping(newSegmentMapping);
- setInitialZone()
- }
- })
- }
-
- // Retrieves the habitat image from the api if it's not loaded already
- Object.keys(habitatImageObject).length === 0 && getHabitatImage()
-
- // Retrieves the habitat image from the api if it's not loaded already
- Object.keys(segmentMapping).length === 0 && getZones()
-
- }, [habitatImageObject, segmentMapping, props, props.filters.zone]);
-
- const selectZone = (element) => {
- if (['path', 'rect'].includes(element.tagName) && element.attributes.inkscapelabel && element.attributes.inkscapelabel.nodeValue) {
- if (selectedZoneSegment) {
- selectedZoneSegment.style['fill-opacity'] = 0;
- }
-
- setZoneSegment(element)
- element.style.fill = "#eeeeee"
- element.style['fill-opacity'] = 0.5;
-
- const zone = segmentMapping[element.attributes.inkscapelabel.nodeValue]
-
- setZoneOrRedirect(zone)
- }
- }
-
- const showTooltip = (evt) => {
- const element = evt.target;
- if (['path', 'rect'].includes(element.tagName) && element.attributes.inkscapelabel && element.attributes.inkscapelabel.nodeValue) {
- const zone = segmentMapping[element.attributes.inkscapelabel.nodeValue]
-
- if (zone) {
- let tooltip = document.getElementById("svg-tooltip");
- tooltip.innerHTML = zone.tooltip_display_text;
- tooltip.style.display = "block";
- tooltip.style.left = evt.pageX + 10 + 'px';
- tooltip.style.top = evt.pageY + 10 + 'px';
- tooltip.style.opacity = 1;
- }
- }
- }
-
- const hideTooltip = () => {
- var tooltip = document.getElementById("svg-tooltip");
- tooltip.style.display = "none";
- }
-
- return Object.keys(habitatImageObject).length > 0 ? (
-
-
{habitatImageObject.name}
-
-
-
selectZone(event.target)} onMouseMove={(event) => showTooltip(event)} onMouseOut={() => hideTooltip()} name={habitatImageObject.image_filename} style={{ "height": 'auto', "width": "100%" }} />
-
-
) :
-}
diff --git a/frontend/src/components/steps/zone/ZoneSelector.jsx b/frontend/src/components/steps/zone/ZoneSelector.jsx
new file mode 100644
index 0000000..b2463f0
--- /dev/null
+++ b/frontend/src/components/steps/zone/ZoneSelector.jsx
@@ -0,0 +1,141 @@
+import { useEffect, useState } from "react";
+import SiteRepository from "../../../repository/SiteRepository";
+import { HabitatSVG } from "../HabitatSVG";
+
+export default function ZoneSelector(props) {
+ const [habitatImageObject, setHabitatImageObject] = useState({});
+ const [segmentMapping, setSegmentMapping] = useState({});
+ const [selectedZoneSegment, setZoneSegment] = useState(null);
+
+ const setZoneOrRedirect = (zone) => {
+ const redirectHabitat = zone && zone.redirect_habitat;
+
+ // If there is a redirect habitat set then redirect otherwise set the zone as state
+ const newFilterState = redirectHabitat
+ ? { habitat: { id: redirectHabitat.id, name: redirectHabitat.name } }
+ : { zone: zone };
+
+ props.updateFilterState(newFilterState);
+ props.setRedirectBack(Boolean(redirectHabitat));
+
+ props.setNextDisabled(false);
+ };
+
+ useEffect(() => {
+ const getHabitatImage = () => {
+ SiteRepository.getHabitatImage(props.filters.habitatImage).then(
+ (response) => {
+ if (response.status === 200) {
+ const imageData = response.data;
+ setHabitatImageObject(imageData);
+ }
+ }
+ );
+ };
+
+ const setInitialZone = () => {
+ if (props.filters.zone) {
+ const zone = props.filters.zone;
+ const zoneSegment = document.querySelectorAll(
+ `.zone-selector-svg svg path[inkscapelabel="${zone.related_svg_segment}"]`
+ )[0];
+
+ // If the previously selected zone segment is located in the diagram then highlight it
+ if (zoneSegment) {
+ setZoneSegment(zoneSegment);
+ zoneSegment.style.fill = "#eeeeee";
+ zoneSegment.style["fill-opacity"] = 0.5;
+ props.setNextDisabled(false);
+ }
+ }
+ };
+
+ const getZones = () => {
+ SiteRepository.getZones().then((response) => {
+ if (response.status === 200) {
+ const zoneData = response.data;
+ let newSegmentMapping = {};
+ zoneData.forEach((zone) => {
+ newSegmentMapping[zone.related_svg_segment] = zone;
+ });
+ setSegmentMapping(newSegmentMapping);
+ setInitialZone();
+ }
+ });
+ };
+
+ // Retrieves the habitat image from the api if it's not loaded already
+ Object.keys(habitatImageObject).length === 0 && getHabitatImage();
+
+ // Retrieves the habitat image from the api if it's not loaded already
+ Object.keys(segmentMapping).length === 0 && getZones();
+ }, [habitatImageObject, segmentMapping, props, props.filters.zone]);
+
+ const selectZone = (element) => {
+ if (
+ ["path", "rect"].includes(element.tagName) &&
+ element.attributes.inkscapelabel &&
+ element.attributes.inkscapelabel.nodeValue
+ ) {
+ if (selectedZoneSegment) {
+ selectedZoneSegment.style["fill-opacity"] = 0;
+ }
+
+ setZoneSegment(element);
+ element.style.fill = "#eeeeee";
+ element.style["fill-opacity"] = 0.5;
+
+ const zone = segmentMapping[element.attributes.inkscapelabel.nodeValue];
+
+ setZoneOrRedirect(zone);
+ }
+ };
+
+ const showTooltip = (evt) => {
+ const element = evt.target;
+ if (
+ ["path", "rect"].includes(element.tagName) &&
+ element.attributes.inkscapelabel &&
+ element.attributes.inkscapelabel.nodeValue
+ ) {
+ const zone = segmentMapping[element.attributes.inkscapelabel.nodeValue];
+
+ if (zone) {
+ let tooltip = document.getElementById("svg-tooltip");
+ tooltip.innerHTML = zone.tooltip_display_text;
+ tooltip.style.display = "block";
+ tooltip.style.left = evt.pageX + 10 + "px";
+ tooltip.style.top = evt.pageY + 10 + "px";
+ tooltip.style.opacity = 1;
+ }
+ }
+ };
+
+ const hideTooltip = () => {
+ var tooltip = document.getElementById("svg-tooltip");
+ tooltip.style.display = "none";
+ };
+
+ return Object.keys(habitatImageObject).length > 0 ? (
+
+
{habitatImageObject.name}
+
+
+
selectZone(event.target)}
+ onMouseMove={(event) => showTooltip(event)}
+ onMouseOut={() => hideTooltip()}
+ name={habitatImageObject.image_filename}
+ style={{ height: "auto", width: "100%" }}
+ />
+
+
+ ) : (
+
+ );
+}
diff --git a/frontend/src/components/steps/zone/ZoneStep.js b/frontend/src/components/steps/zone/ZoneStep.js
deleted file mode 100644
index 2ac3fe5..0000000
--- a/frontend/src/components/steps/zone/ZoneStep.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import Step from '../Step';
-import ZoneSelector from './ZoneSelector'
-import StepInformation from '../StepInformation';
-import staticText from '../../../assets/data/staticText.json'
-import zoneBackgroundImage from '../../../assets/img/stepBackgrounds/step4.jpg';
-
-export default function ZoneStep(props) {
- const zoneInfoPanel = (
- {staticText.steps.zone.description}}
- />
- )
-
- const zoneSelectionPanel = (
-
-
-
- )
-
- return (
-
- )
-}
diff --git a/frontend/src/components/steps/zone/ZoneStep.jsx b/frontend/src/components/steps/zone/ZoneStep.jsx
new file mode 100644
index 0000000..e4ebf3b
--- /dev/null
+++ b/frontend/src/components/steps/zone/ZoneStep.jsx
@@ -0,0 +1,37 @@
+import Step from "../Step";
+import ZoneSelector from "./ZoneSelector";
+import StepInformation from "../StepInformation";
+import staticText from "../../../assets/data/staticText.json";
+import zoneBackgroundImage from "../../../assets/img/stepBackgrounds/step4.jpg";
+
+export default function ZoneStep(props) {
+ const zoneInfoPanel = (
+ {staticText.steps.zone.description}}
+ />
+ );
+
+ const zoneSelectionPanel = (
+
+
+
+ );
+
+ return (
+
+ );
+}
diff --git a/frontend/src/index.js b/frontend/src/index.js
index c904682..f7fe04d 100644
--- a/frontend/src/index.js
+++ b/frontend/src/index.js
@@ -1,17 +1,14 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import { createTheme, ThemeProvider } from '@mui/material/styles';
-import reportWebVitals from './reportWebVitals';
-import {
- createBrowserRouter,
- RouterProvider,
-} from 'react-router-dom';
-import MainPage from './pages/MainPage';
+import React from "react";
+import ReactDOM from "react-dom";
+import { createTheme, ThemeProvider } from "@mui/material/styles";
+import reportWebVitals from "./reportWebVitals";
+import { createBrowserRouter, RouterProvider } from "react-router-dom";
+import MainPage from "./pages/MainPage";
// Styles
-import './assets/styles/main.scss';
-import 'bootstrap/dist/css/bootstrap.min.css';
-import ApplyPage from './pages/ApplyPage';
+import "./assets/styles/main.scss";
+import "bootstrap/dist/css/bootstrap.min.css";
+import ApplyPage from "./pages/ApplyPage";
const router = createBrowserRouter([
{
@@ -26,10 +23,10 @@ const router = createBrowserRouter([
const darkTheme = createTheme({
palette: {
- mode: 'dark',
+ mode: "dark",
},
typography: {
- fontFamily: 'Poppins, sans-serif',
+ fontFamily: "Poppins, sans-serif",
},
});
@@ -41,7 +38,7 @@ ReactDOM.render(
,
- document.getElementById('root')
+ document.getElementById("root")
);
// If you want to start measuring performance in your app, pass a function
diff --git a/frontend/src/repository/LocationRepository.js b/frontend/src/repository/LocationRepository.js
index aa63193..bfcdb48 100644
--- a/frontend/src/repository/LocationRepository.js
+++ b/frontend/src/repository/LocationRepository.js
@@ -1,40 +1,55 @@
import API from "./Repository";
-
const LocationRepsostory = {
+ getSoilDetails(filters) {
+ return API.get(`/soil/`, { params: filters });
+ },
- getSoilDetails(filters) {
- return API.get(`/soil/`, { params: filters });
- },
+ getEcologicalDistrictDetails(filters) {
+ return API.get(`/ecologicaldistrict/`, { params: filters });
+ },
- getEcologicalDistrictDetails(filters) {
- return API.get(`/ecologicaldistrict/`, { params: filters });
- },
+ getRegionDetails(filters) {
+ return API.get(`/region/`, { params: filters });
+ },
- getRegionDetails(filters) {
- return API.get(`/region/`, { params: filters });
- },
+ getPropertyDetails(filters) {
+ return API.get(`/address/`, { params: filters });
+ },
- getPropertyDetails(filters) {
- return API.get(`/address/`, { params: filters });
- },
+ async getLocationData(filters) {
+ const [
+ soilDetails,
+ ecologicalDistrictDetails,
+ propertyDetails,
+ regionDetails,
+ ] = await Promise.all([
+ this.getSoilDetails(filters),
+ this.getEcologicalDistrictDetails(filters),
+ this.getPropertyDetails(filters),
+ this.getRegionDetails(filters),
+ ]);
- async getLocationData(filters) {
- const [soilDetails, ecologicalDistrictDetails, propertyDetails, regionDetails] = await Promise.all([
- this.getSoilDetails(filters),
- this.getEcologicalDistrictDetails(filters),
- this.getPropertyDetails(filters),
- this.getRegionDetails(filters)
- ]);
+ let locationData = {};
+ locationData =
+ soilDetails.status === 200
+ ? Object.assign(locationData, soilDetails.data[0])
+ : locationData;
+ locationData =
+ ecologicalDistrictDetails.status === 200
+ ? Object.assign(locationData, ecologicalDistrictDetails.data[0])
+ : locationData;
+ locationData =
+ propertyDetails.status === 200
+ ? Object.assign(locationData, propertyDetails.data)
+ : locationData;
+ locationData =
+ regionDetails.status === 200
+ ? Object.assign(locationData, regionDetails.data)
+ : locationData;
- let locationData = {};
- locationData = soilDetails.status === 200 ? Object.assign(locationData, soilDetails.data[0]) : locationData;
- locationData = ecologicalDistrictDetails.status === 200 ? Object.assign(locationData, ecologicalDistrictDetails.data[0]) : locationData;
- locationData = propertyDetails.status === 200 ? Object.assign(locationData, propertyDetails.data) : locationData;
- locationData = regionDetails.status === 200 ? Object.assign(locationData, regionDetails.data) : locationData;
-
- return locationData
- }
-}
+ return locationData;
+ },
+};
export default LocationRepsostory;
diff --git a/frontend/src/repository/PlantRepository.js b/frontend/src/repository/PlantRepository.js
index d321df9..59589e4 100644
--- a/frontend/src/repository/PlantRepository.js
+++ b/frontend/src/repository/PlantRepository.js
@@ -1,19 +1,20 @@
import Repository from "./Repository";
const PlantRepository = {
+ getFilteredPlants(filters) {
+ return Repository.get(`/plants/`, { params: filters });
+ },
- getFilteredPlants(filters) {
- return Repository.get(`/plants/`, { params: filters });
- },
+ getPlantsCSV(filters) {
+ return Repository.get("/download/csv/", { params: filters });
+ },
- getPlantsCSV(filters) {
- return Repository.get('/download/csv/', { params: filters })
- },
-
- getPlantsPDF(filters) {
- return Repository.get('/download/pdf/', { params: filters, responseType: 'arraybuffer' })
- }
-
-}
+ getPlantsPDF(filters) {
+ return Repository.get("/download/pdf/", {
+ params: filters,
+ responseType: "arraybuffer",
+ });
+ },
+};
export default PlantRepository;
diff --git a/frontend/src/repository/Repository.js b/frontend/src/repository/Repository.js
index 555a907..0bc49af 100644
--- a/frontend/src/repository/Repository.js
+++ b/frontend/src/repository/Repository.js
@@ -1,8 +1,11 @@
-import axios from "axios"
+import axios from "axios";
// Create the axios object
const repo = axios.create({
- baseURL: window.location.hostname === 'localhost' ? "http://localhost:9000/api" : "/api",
+ baseURL:
+ window.location.hostname === "localhost"
+ ? "http://localhost:9000/api"
+ : "/api",
});
repo.defaults.headers.post["access-control-allow-origin"] = "*";
diff --git a/frontend/src/repository/SiteRepository.js b/frontend/src/repository/SiteRepository.js
index a3c2b6d..d298d62 100644
--- a/frontend/src/repository/SiteRepository.js
+++ b/frontend/src/repository/SiteRepository.js
@@ -1,19 +1,17 @@
import Repository from "./Repository";
const SiteRepository = {
+ getHabitats() {
+ return Repository.get(`/habitats/`);
+ },
- getHabitats() {
- return Repository.get(`/habitats/`);
- },
+ getZones() {
+ return Repository.get(`/zones/`);
+ },
- getZones() {
- return Repository.get(`/zones/`);
- },
+ getHabitatImage(habitatImageID) {
+ return Repository.get(`/habitatimage/${habitatImageID}/`);
+ },
+};
- getHabitatImage(habitatImageID) {
- return Repository.get(`/habitatimage/${habitatImageID}/`);
- }
-
-}
-
-export default SiteRepository;
\ No newline at end of file
+export default SiteRepository;