From a03de013de860e8bb1842612de60de3ff4e8d9a6 Mon Sep 17 00:00:00 2001 From: Matthew Northcott Date: Wed, 8 Feb 2023 14:15:49 +1300 Subject: [PATCH] [#40] Add /apply route with address selector --- frontend/src/assets/data/staticText.json | 4 + frontend/src/components/Stepper.js | 45 +++++----- .../steps/address/AddressSearch.jsx | 88 +++++++++++++++++++ .../components/steps/address/AddressStep.jsx | 29 ++++++ frontend/src/index.js | 6 +- frontend/src/pages/ApplyPage.jsx | 45 ++++++++++ frontend/src/pages/MainPage.js | 39 -------- frontend/src/pages/MainPage.jsx | 51 +++++++++++ frontend/src/pages/RegisterPage.jsx | 5 -- 9 files changed, 240 insertions(+), 72 deletions(-) create mode 100644 frontend/src/components/steps/address/AddressSearch.jsx create mode 100644 frontend/src/components/steps/address/AddressStep.jsx create mode 100644 frontend/src/pages/ApplyPage.jsx delete mode 100644 frontend/src/pages/MainPage.js create mode 100644 frontend/src/pages/MainPage.jsx delete mode 100644 frontend/src/pages/RegisterPage.jsx diff --git a/frontend/src/assets/data/staticText.json b/frontend/src/assets/data/staticText.json index ce6155e..56a12e9 100644 --- a/frontend/src/assets/data/staticText.json +++ b/frontend/src/assets/data/staticText.json @@ -1,5 +1,9 @@ { "steps": { + "address": { + "title": "Right Plant Right Place Right Time\nPlant Selector Tool for New Zealand.", + "description": "Your native plant selection starts here! Register by entering your address. On the following pages you will provide more details on your project until the system has enough information to create your plant species list and planting plan. To start, click on the map and pan and zoom to the site location. Once the location is selected, click on the “next step” button to complete the process. Repeat this process for sites at different locations." + }, "location": { "title": "Right Plant Right Place Right Time\nPlant Selector Tool for New Zealand.", "description": "Your native plant selection starts here! Use the map to select a planting site location within New Zealand. On the following pages you will provide more details on your project until the system has enough information to create your plant species list and planting plan. To start, click on the map and pan and zoom to the site location. Once the location is selected, click on the “next step” button to complete the process. Repeat this process for sites at different locations." diff --git a/frontend/src/components/Stepper.js b/frontend/src/components/Stepper.js index b914f72..b659cd6 100644 --- a/frontend/src/components/Stepper.js +++ b/frontend/src/components/Stepper.js @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { useState } from 'react'; import Box from '@mui/material/Box'; import Stepper from '@mui/material/Stepper'; import Step from '@mui/material/Step'; @@ -6,26 +6,11 @@ import StepLabel from '@mui/material/StepLabel'; import Button from '@mui/material/Button'; import Tooltip from '@mui/material/Tooltip'; -import LocationStep from './steps/location/LocationStep' -import SoilStep from './steps/soilvariant/SoilStep' -import HabitatStep from './steps/habitat/HabitatStep'; -import ZoneStep from './steps/zone/ZoneStep'; -import SummaryStep from './steps/summary/SummaryStep'; -import ResultsStep from './steps/results/ResultsStep' - -const steps = [ - { 'label': 'Select location', 'component': LocationStep, 'tooltip': "Click on a location on the map" }, - { 'label': 'Choose soil', 'component': SoilStep, 'tooltip': "Describe the moisture content of your soil" }, - { 'label': 'Choose habitat', 'component': HabitatStep, 'tooltip': "Specify type of landscape to be planted" }, - { 'label': 'Select zone', 'component': ZoneStep, 'tooltip': "Specify geographical detail" }, - { 'label': 'Summary', 'component': SummaryStep, 'tooltip': "Check your inputs" }, - { 'label': 'Results', 'component': ResultsStep, 'tooltip': "List of plant species and user guide" } -]; - -export default function StepperWizard(props) { - const [activeStep, setActiveStep] = React.useState(0); - const [nextDisabled, setNextDisabled] = React.useState(true); - const [redirectBack, setRedirectBack] = React.useState(false); +export default function StepperWizard({ steps }) { + const [filters, setFilters] = useState({}); + const [activeStep, setActiveStep] = useState(0); + const [nextDisabled, setNextDisabled] = useState(true); + const [redirectBack, setRedirectBack] = useState(false); const resetStepState = () => { setNextDisabled(true); @@ -49,7 +34,11 @@ export default function StepperWizard(props) { const handleReset = () => { setActiveStep(0); resetStepState(); - props.resetFilterState() + setFilters({}); + }; + + const updateFilterState = (newFilters) => { + setFilters(f => ({...f, ...newFilters})); }; let CurrentStep = activeStep >= steps.length ? steps[steps.length - 1].component : steps[activeStep].component; @@ -67,8 +56,14 @@ export default function StepperWizard(props) { ); })} - - + <> + setFilters({})} + setNextDisabled={setNextDisabled} + setRedirectBack={setRedirectBack} + /> : } - + ); } diff --git a/frontend/src/components/steps/address/AddressSearch.jsx b/frontend/src/components/steps/address/AddressSearch.jsx new file mode 100644 index 0000000..1bf9b2a --- /dev/null +++ b/frontend/src/components/steps/address/AddressSearch.jsx @@ -0,0 +1,88 @@ +import { useState, useRef, useEffect } from 'react'; +import { InputAdornment, TextField } from '@mui/material'; +import PlaceIcon from '@mui/icons-material/Place'; +import Box from '@mui/material/Box'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemText from '@mui/material/ListItemText'; +import LocationRepsostory from '../../../repository/LocationRepository'; +import { CircularProgress } from "@mui/material"; + + +const AddressSearchSuggestions = ({results, onClick}) => ( + (Array.isArray(results) && results.length > 0) + ? + + {results.map((r) => ( + + onClick(r)}> + + + + ))} + + + : null); + +const AddressSearch = ({filters, updateFilterState, resetFilterState, setNextDisabled, setRedirectBack, classNames}) => { + const [value, setValue] = useState(""); + const [enable, setEnable] = useState(true); + const [results, setResults] = useState([]); + const [isLoading, setIsLoading] = useState(false); + + useEffect(() => { + setResults([]); + + if (enable && value && value.length > 5) { + setNextDisabled(true); + const timer = setTimeout(() => { + setIsLoading(true); + LocationRepsostory.getPropertyDetails({search: value}).then(resp => { + setResults(resp.data); + setIsLoading(false); + }); + }, 500); + + return () => clearTimeout(timer); + } + }, [value, enable, setNextDisabled]); + + return ( +
+ + {isLoading ? : } + + ) + }} + autoComplete="off" + onChange={(e) => { + setEnable(true); + setValue(e.target.value); + }} + value={value} + /> + { + setValue(r.address); + updateFilterState({ + coordinates: { + lng: r.coordinates[0], + lat: r.coordinates[1], + }, + }); + setNextDisabled(false); + setEnable(false); + }} + /> +
); +}; + +export default AddressSearch; diff --git a/frontend/src/components/steps/address/AddressStep.jsx b/frontend/src/components/steps/address/AddressStep.jsx new file mode 100644 index 0000000..de705df --- /dev/null +++ b/frontend/src/components/steps/address/AddressStep.jsx @@ -0,0 +1,29 @@ +import Step from '../Step'; +import StepInformation from '../StepInformation'; +import staticText from '../../../assets/data/staticText.json' +import addressBackgroundImage from '../../../assets/img/stepBackgrounds/step1.jpg'; +import AddressSearch from './AddressSearch'; + + +const AddressStep = (props) => { + + const addressPanel = ( +
+ {staticText.steps.address.description}

} + /> +
+ +
+
+ ); + + return ( + ); +}; + +export default AddressStep; diff --git a/frontend/src/index.js b/frontend/src/index.js index f67b23a..c904682 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -11,7 +11,7 @@ import MainPage from './pages/MainPage'; // Styles import './assets/styles/main.scss'; import 'bootstrap/dist/css/bootstrap.min.css'; -import RegisterPage from './pages/RegisterPage'; +import ApplyPage from './pages/ApplyPage'; const router = createBrowserRouter([ { @@ -19,8 +19,8 @@ const router = createBrowserRouter([ element: , }, { - path: "/register", - element: , + path: "/apply", + element: , }, ]); diff --git a/frontend/src/pages/ApplyPage.jsx b/frontend/src/pages/ApplyPage.jsx new file mode 100644 index 0000000..a4f1879 --- /dev/null +++ b/frontend/src/pages/ApplyPage.jsx @@ -0,0 +1,45 @@ +import { Container } from "reactstrap"; +import Stepper from "../components/Stepper"; +import Header from "../components/Header"; +import AddressStep from "../components/steps/address/AddressStep"; +import SoilStep from "../components/steps/soilvariant/SoilStep"; +import HabitatStep from "../components/steps/habitat/HabitatStep"; +import ZoneStep from "../components/steps/zone/ZoneStep"; +import SummaryStep from "../components/steps/summary/SummaryStep"; + +const ApplyPage = () => ( + +
+ + +); + +export default ApplyPage; diff --git a/frontend/src/pages/MainPage.js b/frontend/src/pages/MainPage.js deleted file mode 100644 index 6f70eb4..0000000 --- a/frontend/src/pages/MainPage.js +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react' -import { Container } from 'reactstrap'; -import Stepper from '../components/Stepper' -import Header from '../components/Header' -export default class MainPage extends React.Component { - - constructor(props) { - super(props); - - this.state = { - filters: {} - } - - this.updateFilterState = this.updateFilterState.bind(this); - this.resetFilterState = this.resetFilterState.bind(this); - } - - - updateFilterState(newFilter) { - this.setState({ filters: Object.assign(this.state.filters, newFilter) }) - } - - resetFilterState() { - this.setState({ filters: {} }) - } - - render() { - return ( - -
- - - ) - } - -} \ No newline at end of file diff --git a/frontend/src/pages/MainPage.jsx b/frontend/src/pages/MainPage.jsx new file mode 100644 index 0000000..7828472 --- /dev/null +++ b/frontend/src/pages/MainPage.jsx @@ -0,0 +1,51 @@ +import { Container } from "reactstrap"; +import Stepper from "../components/Stepper"; +import Header from "../components/Header"; +import LocationStep from "../components/steps/location/LocationStep"; +import SoilStep from "../components/steps/soilvariant/SoilStep"; +import HabitatStep from "../components/steps/habitat/HabitatStep"; +import ZoneStep from "../components/steps/zone/ZoneStep"; +import SummaryStep from "../components/steps/summary/SummaryStep"; +import ResultsStep from "../components/steps/results/ResultsStep"; + +const MainPage = () => ( + +
+ + +); + +export default MainPage; diff --git a/frontend/src/pages/RegisterPage.jsx b/frontend/src/pages/RegisterPage.jsx deleted file mode 100644 index 1cd579e..0000000 --- a/frontend/src/pages/RegisterPage.jsx +++ /dev/null @@ -1,5 +0,0 @@ -const RegisterPage = () => { - return <>; -}; - -export default RegisterPage;