[#44] Loading Indicator
- add loading indicator to plant list - format PlantList.js and ResultsStep.js
This commit is contained in:
parent
ddcff48f5b
commit
47b6c48aea
2 changed files with 213 additions and 132 deletions
|
@ -1,25 +1,27 @@
|
||||||
import * as React from 'react';
|
import * as React from "react";
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from "prop-types";
|
||||||
import { useTheme } from '@mui/material/styles';
|
import { useTheme } from "@mui/material/styles";
|
||||||
import Box from '@mui/material/Box';
|
import Box from "@mui/material/Box";
|
||||||
import Table from '@mui/material/Table';
|
import Stack from "@mui/material/Stack";
|
||||||
import TableBody from '@mui/material/TableBody';
|
import Table from "@mui/material/Table";
|
||||||
import TableCell from '@mui/material/TableCell';
|
import TableBody from "@mui/material/TableBody";
|
||||||
import TableContainer from '@mui/material/TableContainer';
|
import TableCell from "@mui/material/TableCell";
|
||||||
import TableFooter from '@mui/material/TableFooter';
|
import TableContainer from "@mui/material/TableContainer";
|
||||||
import TablePagination from '@mui/material/TablePagination';
|
import TableFooter from "@mui/material/TableFooter";
|
||||||
import TableRow from '@mui/material/TableRow';
|
import TablePagination from "@mui/material/TablePagination";
|
||||||
import TableHead from '@mui/material/TableHead';
|
import TableRow from "@mui/material/TableRow";
|
||||||
import Paper from '@mui/material/Paper';
|
import TableHead from "@mui/material/TableHead";
|
||||||
import IconButton from '@mui/material/IconButton';
|
import Paper from "@mui/material/Paper";
|
||||||
import FirstPageIcon from '@mui/icons-material/FirstPage';
|
import IconButton from "@mui/material/IconButton";
|
||||||
import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft';
|
import FirstPageIcon from "@mui/icons-material/FirstPage";
|
||||||
import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight';
|
import KeyboardArrowLeft from "@mui/icons-material/KeyboardArrowLeft";
|
||||||
import LastPageIcon from '@mui/icons-material/LastPage';
|
import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight";
|
||||||
import { styled } from '@mui/material/styles';
|
import LastPageIcon from "@mui/icons-material/LastPage";
|
||||||
import Tooltip, { tooltipClasses } from '@mui/material/Tooltip';
|
import { styled } from "@mui/material/styles";
|
||||||
import staticText from '../../../assets/data/staticText.json'
|
import Tooltip, { tooltipClasses } from "@mui/material/Tooltip";
|
||||||
import forestGraphic from '../../../assets/img/habitats/1a_Forest_Section.png';
|
import staticText from "../../../assets/data/staticText.json";
|
||||||
|
import forestGraphic from "../../../assets/img/habitats/1a_Forest_Section.png";
|
||||||
|
import { CircularProgress } from "@mui/material";
|
||||||
|
|
||||||
function TablePaginationActions(props) {
|
function TablePaginationActions(props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
@ -48,28 +50,36 @@ function TablePaginationActions(props) {
|
||||||
disabled={page === 0}
|
disabled={page === 0}
|
||||||
aria-label="first page"
|
aria-label="first page"
|
||||||
>
|
>
|
||||||
{theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
|
{theme.direction === "rtl" ? <LastPageIcon /> : <FirstPageIcon />}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={handleBackButtonClick}
|
onClick={handleBackButtonClick}
|
||||||
disabled={page === 0}
|
disabled={page === 0}
|
||||||
aria-label="previous page"
|
aria-label="previous page"
|
||||||
>
|
>
|
||||||
{theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
|
{theme.direction === "rtl" ? (
|
||||||
|
<KeyboardArrowRight />
|
||||||
|
) : (
|
||||||
|
<KeyboardArrowLeft />
|
||||||
|
)}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={handleNextButtonClick}
|
onClick={handleNextButtonClick}
|
||||||
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
|
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
|
||||||
aria-label="next page"
|
aria-label="next page"
|
||||||
>
|
>
|
||||||
{theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
|
{theme.direction === "rtl" ? (
|
||||||
|
<KeyboardArrowLeft />
|
||||||
|
) : (
|
||||||
|
<KeyboardArrowRight />
|
||||||
|
)}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={handleLastPageButtonClick}
|
onClick={handleLastPageButtonClick}
|
||||||
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
|
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
|
||||||
aria-label="last page"
|
aria-label="last page"
|
||||||
>
|
>
|
||||||
{theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
|
{theme.direction === "rtl" ? <FirstPageIcon /> : <LastPageIcon />}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -86,6 +96,14 @@ export default function PlantResultsTable(props) {
|
||||||
const [page, setPage] = React.useState(0);
|
const [page, setPage] = React.useState(0);
|
||||||
const [rowsPerPage, setRowsPerPage] = React.useState(25);
|
const [rowsPerPage, setRowsPerPage] = React.useState(25);
|
||||||
|
|
||||||
|
let rows = [];
|
||||||
|
if (props.rows) {
|
||||||
|
rows =
|
||||||
|
rowsPerPage > 0
|
||||||
|
? props.rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
||||||
|
: props.rows;
|
||||||
|
}
|
||||||
|
|
||||||
// Avoid a layout jump when reaching the last page with empty rows.
|
// Avoid a layout jump when reaching the last page with empty rows.
|
||||||
const emptyRows =
|
const emptyRows =
|
||||||
page > 0 ? Math.max(0, (1 + page) * rowsPerPage - props.rows.length) : 0;
|
page > 0 ? Math.max(0, (1 + page) * rowsPerPage - props.rows.length) : 0;
|
||||||
|
@ -108,11 +126,15 @@ export default function PlantResultsTable(props) {
|
||||||
});
|
});
|
||||||
|
|
||||||
const forestDiagramInformation = (
|
const forestDiagramInformation = (
|
||||||
<div style={{ "width": "100%" }}>
|
<div style={{ width: "100%" }}>
|
||||||
<p>{staticText.steps.results.forestDiagramDescription}</p>
|
<p>{staticText.steps.results.forestDiagramDescription}</p>
|
||||||
<img src={forestGraphic} style={{ "width": "100%" }} />
|
<img
|
||||||
|
src={forestGraphic}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
alt={staticText.steps.results.forestDiagramDescription}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableContainer component={Paper}>
|
<TableContainer component={Paper}>
|
||||||
|
@ -121,22 +143,35 @@ export default function PlantResultsTable(props) {
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>Names</TableCell>
|
<TableCell>Names</TableCell>
|
||||||
<CustomWidthTooltip arrow title={forestDiagramInformation}>
|
<CustomWidthTooltip arrow title={forestDiagramInformation}>
|
||||||
<TableCell align="right">Growth Form / Max Height (m) / Spacing (m) / Forest Position</TableCell>
|
<TableCell align="right">
|
||||||
|
Growth Form / Max Height (m) / Spacing (m) / Forest Position
|
||||||
|
</TableCell>
|
||||||
</CustomWidthTooltip>
|
</CustomWidthTooltip>
|
||||||
<TableCell align="right">Moisture Preferences</TableCell>
|
<TableCell align="right">Moisture Preferences</TableCell>
|
||||||
<TableCell align="right">Tolerances (Water / Drought / Frost / Salinity)</TableCell>
|
<TableCell align="right">
|
||||||
|
Tolerances (Water / Drought / Frost / Salinity)
|
||||||
|
</TableCell>
|
||||||
<TableCell align="right">Ecosystem Services</TableCell>
|
<TableCell align="right">Ecosystem Services</TableCell>
|
||||||
<TableCell align="right">Carbon Sequestration Rate</TableCell>
|
<TableCell align="right">Carbon Sequestration Rate</TableCell>
|
||||||
<TableCell align="right">Planting Stage</TableCell>
|
<TableCell align="right">Planting Stage</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{(rowsPerPage > 0
|
{rows.length === 0 && (
|
||||||
? props.rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
<TableRow style={{ height: 150 }}>
|
||||||
: props.rows
|
<TableCell colSpan={7}>
|
||||||
).map((row) => (
|
<Stack alignItems="center">
|
||||||
|
<CircularProgress />
|
||||||
|
</Stack>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
{rows.length > 0 &&
|
||||||
|
rows.map((row) => (
|
||||||
<TableRow key={row.name}>
|
<TableRow key={row.name}>
|
||||||
<TableCell component="th" scope="row">{row.name}</TableCell>
|
<TableCell component="th" scope="row">
|
||||||
|
{row.name}
|
||||||
|
</TableCell>
|
||||||
<TableCell align="right">{row.growthForm}</TableCell>
|
<TableCell align="right">{row.growthForm}</TableCell>
|
||||||
<TableCell align="right">{row.moisturePreferences}</TableCell>
|
<TableCell align="right">{row.moisturePreferences}</TableCell>
|
||||||
<TableCell align="right">{row.plantTolerances}</TableCell>
|
<TableCell align="right">{row.plantTolerances}</TableCell>
|
||||||
|
@ -148,7 +183,7 @@ export default function PlantResultsTable(props) {
|
||||||
|
|
||||||
{emptyRows > 0 && (
|
{emptyRows > 0 && (
|
||||||
<TableRow style={{ height: 53 * emptyRows }}>
|
<TableRow style={{ height: 53 * emptyRows }}>
|
||||||
<TableCell colSpan={6} />
|
<TableCell colSpan={7} />
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
|
@ -156,14 +191,14 @@ export default function PlantResultsTable(props) {
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TablePagination
|
<TablePagination
|
||||||
className="plant-list-pagination"
|
className="plant-list-pagination"
|
||||||
rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
|
rowsPerPageOptions={[5, 10, 25, { label: "All", value: -1 }]}
|
||||||
colSpan={7}
|
colSpan={7}
|
||||||
count={props.rows.length}
|
count={props.rows.length}
|
||||||
rowsPerPage={rowsPerPage}
|
rowsPerPage={rowsPerPage}
|
||||||
page={page}
|
page={page}
|
||||||
SelectProps={{
|
SelectProps={{
|
||||||
inputProps: {
|
inputProps: {
|
||||||
'aria-label': 'rows per page',
|
"aria-label": "rows per page",
|
||||||
},
|
},
|
||||||
native: true,
|
native: true,
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -1,35 +1,51 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import Step from '../Step';
|
import Step from "../Step";
|
||||||
import PlantList from './PlantList'
|
import PlantList from "./PlantList";
|
||||||
import Stack from '@mui/material/Stack';
|
import Stack from "@mui/material/Stack";
|
||||||
import Button from '@mui/material/Button';
|
import Button from "@mui/material/Button";
|
||||||
import PlantRepository from '../../../repository/PlantRepository'
|
import PlantRepository from "../../../repository/PlantRepository";
|
||||||
import { Typography, Box } from '@mui/material';
|
import { Typography, Box } from "@mui/material";
|
||||||
import resultsBackgroundImage from '../../../assets/img/stepBackgrounds/step6.jpg';
|
import resultsBackgroundImage from "../../../assets/img/stepBackgrounds/step6.jpg";
|
||||||
import staticText from '../../../assets/data/staticText.json'
|
import staticText from "../../../assets/data/staticText.json";
|
||||||
|
|
||||||
const RESULTS_DESCRIPTION = <Typography>Please review the plant species list – it can be saved as a CSV file or appended to a planting plan guidebook. Additional information on each species can be obtained by entering the plant species name into the search box at <a href='https://inaturalist.nz' target='blank'>inaturalist.nz</a> or in the "search flora" box at <a href="https://www.nzpcn.org.nz/" target="blank">www.nzpcn.org.nz</a>. Click the "Download PDF" button to create a planting plan guidebook specific to your project site..</Typography>
|
const RESULTS_DESCRIPTION = (
|
||||||
|
<Typography>
|
||||||
|
Please review the plant species list. It can be saved as a CSV file or
|
||||||
|
appended to a planting plan guidebook. Additional information on each
|
||||||
|
species can be obtained by entering the plant species name into the search
|
||||||
|
box at{" "}
|
||||||
|
<a href="https://inaturalist.nz" target="blank">
|
||||||
|
inaturalist.nz
|
||||||
|
</a>{" "}
|
||||||
|
or in the "search flora" box at{" "}
|
||||||
|
<a href="https://www.nzpcn.org.nz/" target="blank">
|
||||||
|
www.nzpcn.org.nz
|
||||||
|
</a>
|
||||||
|
. Click the "Download PDF" button to create a planting plan guidebook
|
||||||
|
specific to your project site.
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
|
||||||
export default function ResultsStep(props) {
|
export default function ResultsStep(props) {
|
||||||
const [plants, setPlants] = useState([]);
|
const [plants, setPlants] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updatePlants = () => {
|
const updatePlants = () => {
|
||||||
PlantRepository.getFilteredPlants(props.filters).then(response => {
|
PlantRepository.getFilteredPlants(props.filters)
|
||||||
|
.then((response) => {
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
setPlants(response.data)
|
setPlants(response.data);
|
||||||
}
|
}
|
||||||
}).catch(e => {
|
|
||||||
this.setState({ plants: ["No plants found."] });
|
|
||||||
})
|
})
|
||||||
}
|
.catch((e) => {
|
||||||
updatePlants()},
|
this.setState({ plants: ["No plants found."] });
|
||||||
[props.filters]);
|
});
|
||||||
|
};
|
||||||
|
updatePlants();
|
||||||
|
}, [props.filters]);
|
||||||
|
|
||||||
|
function createData(
|
||||||
function createData(name, growthForm, moisturePreferences, plantTolerances, ecosystemServices, carbonSequestration, plantingStage) {
|
|
||||||
return {
|
|
||||||
name,
|
name,
|
||||||
growthForm,
|
growthForm,
|
||||||
moisturePreferences,
|
moisturePreferences,
|
||||||
|
@ -37,6 +53,15 @@ export default function ResultsStep(props) {
|
||||||
ecosystemServices,
|
ecosystemServices,
|
||||||
carbonSequestration,
|
carbonSequestration,
|
||||||
plantingStage
|
plantingStage
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
growthForm,
|
||||||
|
moisturePreferences,
|
||||||
|
plantTolerances,
|
||||||
|
ecosystemServices,
|
||||||
|
carbonSequestration,
|
||||||
|
plantingStage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,45 +76,66 @@ export default function ResultsStep(props) {
|
||||||
plant.carbon_sequestration,
|
plant.carbon_sequestration,
|
||||||
plant.stage
|
plant.stage
|
||||||
);
|
);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const download = (response, fileType, fileName) => {
|
const download = (response, fileType, fileName) => {
|
||||||
const url = window.URL.createObjectURL(new Blob([response.data], {type : fileType }));
|
const url = window.URL.createObjectURL(
|
||||||
const link = document.createElement('a');
|
new Blob([response.data], { type: fileType })
|
||||||
|
);
|
||||||
|
const link = document.createElement("a");
|
||||||
link.href = url;
|
link.href = url;
|
||||||
link.setAttribute('download', fileName);
|
link.setAttribute("download", fileName);
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
}
|
};
|
||||||
|
|
||||||
const downloadCSV = () => {
|
const downloadCSV = () => {
|
||||||
PlantRepository.getPlantsCSV(props.filters).then(response => {
|
PlantRepository.getPlantsCSV(props.filters).then((response) => {
|
||||||
download(response, "text/csv", "plants.csv")
|
download(response, "text/csv", "plants.csv");
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const downloadPDF = () => {
|
const downloadPDF = () => {
|
||||||
PlantRepository.getPlantsPDF(props.filters).then(response => {
|
PlantRepository.getPlantsPDF(props.filters).then((response) => {
|
||||||
download(response, "application/pdf", "planting_guide.pdf")
|
download(response, "application/pdf", "planting_guide.pdf");
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const stepContent = (
|
const stepContent = (
|
||||||
<div className="py-4">
|
<div className="py-4">
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }} className="pb-4">
|
<Box
|
||||||
<Typography variant='h5'>{staticText.steps.results.title}</Typography>
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
className="pb-4"
|
||||||
|
>
|
||||||
|
<Typography variant="h5">{staticText.steps.results.title}</Typography>
|
||||||
<Stack spacing={2} direction="row" justifyContent="end">
|
<Stack spacing={2} direction="row" justifyContent="end">
|
||||||
<Button variant="contained" onClick={() => downloadPDF()}>Download PDF</Button>
|
<Button variant="contained" onClick={() => downloadPDF()}>
|
||||||
<Button variant="contained" onClick={() => downloadCSV()}>Download CSV</Button>
|
Download PDF
|
||||||
|
</Button>
|
||||||
|
<Button variant="contained" onClick={() => downloadCSV()}>
|
||||||
|
Download CSV
|
||||||
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
<Typography variant='body2' sx={{ paddingRight: '100px', paddingBottom: '20px' }}>{RESULTS_DESCRIPTION}</Typography>
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{ paddingRight: "100px", paddingBottom: "20px" }}
|
||||||
|
>
|
||||||
|
{RESULTS_DESCRIPTION}
|
||||||
|
</Typography>
|
||||||
<PlantList rows={getTableRows()} />
|
<PlantList rows={getTableRows()} />
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Step contentComponent={stepContent} backgroundImage={resultsBackgroundImage} />
|
<Step
|
||||||
)
|
contentComponent={stepContent}
|
||||||
|
backgroundImage={resultsBackgroundImage}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue