[#40] Add /apply route with address selector

This commit is contained in:
Matthew Northcott 2023-02-08 14:15:49 +13:00
parent 108e3e0f67
commit a03de013de
9 changed files with 240 additions and 72 deletions

View file

@ -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."

View file

@ -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) {
);
})}
</Stepper>
<React.Fragment>
<CurrentStep {...props} setNextDisabled={setNextDisabled} setRedirectBack={setRedirectBack} />
<>
<CurrentStep
filters={filters}
updateFilterState={updateFilterState}
resetFilterState={() => setFilters({})}
setNextDisabled={setNextDisabled}
setRedirectBack={setRedirectBack}
/>
<Box sx={{ display: 'flex', flexDirection: 'row', pt: 2, pb: 2, paddingRight: '3vw', paddingLeft: '3vw' }}>
<Button
color="inherit"
@ -82,7 +77,7 @@ export default function StepperWizard(props) {
{activeStep === steps.length - 1 ?
<Button onClick={handleReset}>Reset</Button> : <Button onClick={handleNext} disabled={nextDisabled}>Next</Button>}
</Box>
</React.Fragment>
</>
</Box>
);
}

View file

@ -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)
? <Box sx={{ width: '100%', bgcolor: 'background.paper' }}>
<List>
{results.map((r) => (
<ListItem disablePadding>
<ListItemButton onClick={() => onClick(r)}>
<ListItemText primary={r.address} />
</ListItemButton>
</ListItem>
))}
</List>
</Box>
: 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 (
<div classNames={classNames}>
<TextField
fullWidth
variant="outlined"
placeholder="Enter address..."
InputProps={{
startAdornment: (
<InputAdornment position="start">
{isLoading ? <CircularProgress size="1.2rem" color="inherit" /> : <PlaceIcon />}
</InputAdornment>
)
}}
autoComplete="off"
onChange={(e) => {
setEnable(true);
setValue(e.target.value);
}}
value={value}
/>
<AddressSearchSuggestions
results={results}
onClick={(r) => {
setValue(r.address);
updateFilterState({
coordinates: {
lng: r.coordinates[0],
lat: r.coordinates[1],
},
});
setNextDisabled(false);
setEnable(false);
}}
/>
</div>);
};
export default AddressSearch;

View file

@ -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 = (
<div className="p-5">
<StepInformation
title={staticText.steps.address.title}
description={<p>{staticText.steps.address.description}</p>}
/>
<div className="p-4">
<AddressSearch {...props} />
</div>
</div>
);
return (
<Step
contentComponent={addressPanel}
backgroundImage={addressBackgroundImage}
/>);
};
export default AddressStep;

View file

@ -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: <MainPage />,
},
{
path: "/register",
element: <RegisterPage />,
path: "/apply",
element: <ApplyPage />,
},
]);

View file

@ -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 = () => (
<Container fluid className="main-container p-0">
<Header />
<Stepper
steps={[
{
label: "Enter address",
component: AddressStep,
tooltip: "Enter your address",
},
{
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: "Submit",
component: SummaryStep,
tooltip: "Submit your application",
},
]}
/>
</Container>
);
export default ApplyPage;

View file

@ -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 (
<Container fluid className='main-container p-0'>
<Header/>
<Stepper
filters={this.state.filters}
updateFilterState={this.updateFilterState}
resetFilterState={this.resetFilterState} />
</Container>
)
}
}

View file

@ -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 = () => (
<Container fluid className="main-container p-0">
<Header />
<Stepper
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",
},
]}
/>
</Container>
);
export default MainPage;

View file

@ -1,5 +0,0 @@
const RegisterPage = () => {
return <></>;
};
export default RegisterPage;