[#44] Loading Indicator #87
2 changed files with 213 additions and 132 deletions
|
@ -1,25 +1,27 @@
|
|||
import * as React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import Box from '@mui/material/Box';
|
||||
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 TableFooter from '@mui/material/TableFooter';
|
||||
import TablePagination from '@mui/material/TablePagination';
|
||||
import TableRow from '@mui/material/TableRow';
|
||||
import TableHead from '@mui/material/TableHead';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import FirstPageIcon from '@mui/icons-material/FirstPage';
|
||||
import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft';
|
||||
import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight';
|
||||
import LastPageIcon from '@mui/icons-material/LastPage';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Tooltip, { tooltipClasses } from '@mui/material/Tooltip';
|
||||
import staticText from '../../../assets/data/staticText.json'
|
||||
import forestGraphic from '../../../assets/img/habitats/1a_Forest_Section.png';
|
||||
import * as React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import Box from "@mui/material/Box";
|
||||
import Stack from "@mui/material/Stack";
|
||||
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 TableFooter from "@mui/material/TableFooter";
|
||||
import TablePagination from "@mui/material/TablePagination";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import TableHead from "@mui/material/TableHead";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import FirstPageIcon from "@mui/icons-material/FirstPage";
|
||||
import KeyboardArrowLeft from "@mui/icons-material/KeyboardArrowLeft";
|
||||
import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight";
|
||||
import LastPageIcon from "@mui/icons-material/LastPage";
|
||||
import { styled } from "@mui/material/styles";
|
||||
import Tooltip, { tooltipClasses } from "@mui/material/Tooltip";
|
||||
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) {
|
||||
const theme = useTheme();
|
||||
|
@ -48,28 +50,36 @@ function TablePaginationActions(props) {
|
|||
disabled={page === 0}
|
||||
aria-label="first page"
|
||||
>
|
||||
{theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
|
||||
{theme.direction === "rtl" ? <LastPageIcon /> : <FirstPageIcon />}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={handleBackButtonClick}
|
||||
disabled={page === 0}
|
||||
aria-label="previous page"
|
||||
>
|
||||
{theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
|
||||
{theme.direction === "rtl" ? (
|
||||
<KeyboardArrowRight />
|
||||
) : (
|
||||
<KeyboardArrowLeft />
|
||||
)}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={handleNextButtonClick}
|
||||
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
|
||||
aria-label="next page"
|
||||
>
|
||||
{theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
|
||||
{theme.direction === "rtl" ? (
|
||||
<KeyboardArrowLeft />
|
||||
) : (
|
||||
<KeyboardArrowRight />
|
||||
)}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={handleLastPageButtonClick}
|
||||
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
|
||||
aria-label="last page"
|
||||
>
|
||||
{theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
|
||||
{theme.direction === "rtl" ? <FirstPageIcon /> : <LastPageIcon />}
|
||||
</IconButton>
|
||||
</Box>
|
||||
);
|
||||
|
@ -86,6 +96,14 @@ export default function PlantResultsTable(props) {
|
|||
const [page, setPage] = React.useState(0);
|
||||
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.
|
||||
const emptyRows =
|
||||
page > 0 ? Math.max(0, (1 + page) * rowsPerPage - props.rows.length) : 0;
|
||||
|
@ -108,47 +126,64 @@ export default function PlantResultsTable(props) {
|
|||
});
|
||||
|
||||
const forestDiagramInformation = (
|
||||
<div style={{ "width": "100%" }}>
|
||||
<div style={{ width: "100%" }}>
|
||||
<p>{staticText.steps.results.forestDiagramDescription}</p>
|
||||
<img src={forestGraphic} style={{ "width": "100%" }} />
|
||||
<img
|
||||
src={forestGraphic}
|
||||
style={{ width: "100%" }}
|
||||
alt={staticText.steps.results.forestDiagramDescription}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
|
||||
return (
|
||||
<TableContainer component={Paper}>
|
||||
<Table size="small" stickyHeader aria-label="Plant table">
|
||||
<TableHead>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Names</TableCell>
|
||||
<CustomWidthTooltip arrow title={forestDiagramInformation} >
|
||||
<TableCell align="right">Growth Form / Max Height (m) / Spacing (m) / Forest Position</TableCell>
|
||||
<CustomWidthTooltip arrow title={forestDiagramInformation}>
|
||||
<TableCell align="right">
|
||||
Growth Form / Max Height (m) / Spacing (m) / Forest Position
|
||||
</TableCell>
|
||||
</CustomWidthTooltip>
|
||||
<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">Carbon Sequestration Rate</TableCell>
|
||||
<TableCell align="right">Planting Stage</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{(rowsPerPage > 0
|
||||
? props.rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
||||
: props.rows
|
||||
).map((row) => (
|
||||
<TableRow key={row.name}>
|
||||
<TableCell component="th" scope="row">{row.name}</TableCell>
|
||||
<TableCell align="right">{row.growthForm}</TableCell>
|
||||
<TableCell align="right">{row.moisturePreferences}</TableCell>
|
||||
<TableCell align="right">{row.plantTolerances}</TableCell>
|
||||
<TableCell align="right">{row.ecosystemServices}</TableCell>
|
||||
<TableCell align="right">{row.carbonSequestration}</TableCell>
|
||||
<TableCell align="right">{row.plantingStage}</TableCell>
|
||||
{rows.length === 0 && (
|
||||
<TableRow style={{ height: 150 }}>
|
||||
<TableCell colSpan={7}>
|
||||
<Stack alignItems="center">
|
||||
<CircularProgress />
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
)}
|
||||
{rows.length > 0 &&
|
||||
rows.map((row) => (
|
||||
<TableRow key={row.name}>
|
||||
<TableCell component="th" scope="row">
|
||||
{row.name}
|
||||
</TableCell>
|
||||
<TableCell align="right">{row.growthForm}</TableCell>
|
||||
<TableCell align="right">{row.moisturePreferences}</TableCell>
|
||||
<TableCell align="right">{row.plantTolerances}</TableCell>
|
||||
<TableCell align="right">{row.ecosystemServices}</TableCell>
|
||||
<TableCell align="right">{row.carbonSequestration}</TableCell>
|
||||
<TableCell align="right">{row.plantingStage}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
|
||||
{emptyRows > 0 && (
|
||||
<TableRow style={{ height: 53 * emptyRows }}>
|
||||
<TableCell colSpan={6} />
|
||||
<TableCell colSpan={7} />
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
|
@ -156,14 +191,14 @@ export default function PlantResultsTable(props) {
|
|||
<TableRow>
|
||||
<TablePagination
|
||||
className="plant-list-pagination"
|
||||
rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
|
||||
rowsPerPageOptions={[5, 10, 25, { label: "All", value: -1 }]}
|
||||
colSpan={7}
|
||||
count={props.rows.length}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
SelectProps={{
|
||||
inputProps: {
|
||||
'aria-label': 'rows per page',
|
||||
"aria-label": "rows per page",
|
||||
},
|
||||
native: true,
|
||||
}}
|
||||
|
|
|
@ -1,95 +1,141 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import Step from '../Step';
|
||||
import PlantList from './PlantList'
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Button from '@mui/material/Button';
|
||||
import PlantRepository from '../../../repository/PlantRepository'
|
||||
import { Typography, Box } from '@mui/material';
|
||||
import resultsBackgroundImage from '../../../assets/img/stepBackgrounds/step6.jpg';
|
||||
import staticText from '../../../assets/data/staticText.json'
|
||||
import Step from "../Step";
|
||||
import PlantList from "./PlantList";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Button from "@mui/material/Button";
|
||||
import PlantRepository from "../../../repository/PlantRepository";
|
||||
import { Typography, Box } from "@mui/material";
|
||||
import resultsBackgroundImage from "../../../assets/img/stepBackgrounds/step6.jpg";
|
||||
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) {
|
||||
const [plants, setPlants] = useState([]);
|
||||
const [plants, setPlants] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const updatePlants = () => {
|
||||
PlantRepository.getFilteredPlants(props.filters).then(response => {
|
||||
if (response.status === 200) {
|
||||
setPlants(response.data)
|
||||
}
|
||||
}).catch(e => {
|
||||
this.setState({ plants: ["No plants found."] });
|
||||
})
|
||||
}
|
||||
updatePlants()},
|
||||
[props.filters]);
|
||||
|
||||
|
||||
function createData(name, growthForm, moisturePreferences, plantTolerances, ecosystemServices, carbonSequestration, plantingStage) {
|
||||
return {
|
||||
name,
|
||||
growthForm,
|
||||
moisturePreferences,
|
||||
plantTolerances,
|
||||
ecosystemServices,
|
||||
carbonSequestration,
|
||||
plantingStage
|
||||
};
|
||||
}
|
||||
|
||||
const getTableRows = () => {
|
||||
return plants.map((plant) => {
|
||||
return createData(
|
||||
plant.display_name,
|
||||
plant.display_growth_form,
|
||||
plant.moisture_preferences,
|
||||
plant.plant_tolerances,
|
||||
plant.ecosystem_services,
|
||||
plant.carbon_sequestration,
|
||||
plant.stage
|
||||
);
|
||||
useEffect(() => {
|
||||
const updatePlants = () => {
|
||||
PlantRepository.getFilteredPlants(props.filters)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
setPlants(response.data);
|
||||
}
|
||||
})
|
||||
}
|
||||
.catch((e) => {
|
||||
this.setState({ plants: ["No plants found."] });
|
||||
});
|
||||
};
|
||||
updatePlants();
|
||||
}, [props.filters]);
|
||||
|
||||
const download = (response, fileType, fileName) => {
|
||||
const url = window.URL.createObjectURL(new Blob([response.data], {type : fileType }));
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.setAttribute('download', fileName);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
}
|
||||
function createData(
|
||||
name,
|
||||
growthForm,
|
||||
moisturePreferences,
|
||||
plantTolerances,
|
||||
ecosystemServices,
|
||||
carbonSequestration,
|
||||
plantingStage
|
||||
) {
|
||||
return {
|
||||
name,
|
||||
growthForm,
|
||||
moisturePreferences,
|
||||
plantTolerances,
|
||||
ecosystemServices,
|
||||
carbonSequestration,
|
||||
plantingStage,
|
||||
};
|
||||
}
|
||||
|
||||
const downloadCSV = () => {
|
||||
PlantRepository.getPlantsCSV(props.filters).then(response => {
|
||||
download(response, "text/csv", "plants.csv")
|
||||
})
|
||||
}
|
||||
const getTableRows = () => {
|
||||
return plants.map((plant) => {
|
||||
return createData(
|
||||
plant.display_name,
|
||||
plant.display_growth_form,
|
||||
plant.moisture_preferences,
|
||||
plant.plant_tolerances,
|
||||
plant.ecosystem_services,
|
||||
plant.carbon_sequestration,
|
||||
plant.stage
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const downloadPDF = () => {
|
||||
PlantRepository.getPlantsPDF(props.filters).then(response => {
|
||||
download(response, "application/pdf", "planting_guide.pdf")
|
||||
})
|
||||
}
|
||||
const download = (response, fileType, fileName) => {
|
||||
const url = window.URL.createObjectURL(
|
||||
new Blob([response.data], { type: fileType })
|
||||
);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.setAttribute("download", fileName);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
};
|
||||
|
||||
const stepContent = (
|
||||
<div className="py-4">
|
||||
<Box 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">
|
||||
<Button variant="contained" onClick={() => downloadPDF()}>Download PDF</Button>
|
||||
<Button variant="contained" onClick={() => downloadCSV()}>Download CSV</Button>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Typography variant='body2' sx={{ paddingRight: '100px', paddingBottom: '20px' }}>{RESULTS_DESCRIPTION}</Typography>
|
||||
<PlantList rows={getTableRows()}/>
|
||||
</div>
|
||||
)
|
||||
const downloadCSV = () => {
|
||||
PlantRepository.getPlantsCSV(props.filters).then((response) => {
|
||||
download(response, "text/csv", "plants.csv");
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Step contentComponent={stepContent} backgroundImage={resultsBackgroundImage} />
|
||||
)
|
||||
const downloadPDF = () => {
|
||||
PlantRepository.getPlantsPDF(props.filters).then((response) => {
|
||||
download(response, "application/pdf", "planting_guide.pdf");
|
||||
});
|
||||
};
|
||||
|
||||
const stepContent = (
|
||||
<div className="py-4">
|
||||
<Box
|
||||
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">
|
||||
<Button variant="contained" onClick={() => downloadPDF()}>
|
||||
Download PDF
|
||||
</Button>
|
||||
<Button variant="contained" onClick={() => downloadCSV()}>
|
||||
Download CSV
|
||||
</Button>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ paddingRight: "100px", paddingBottom: "20px" }}
|
||||
>
|
||||
{RESULTS_DESCRIPTION}
|
||||
</Typography>
|
||||
<PlantList rows={getTableRows()} />
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Step
|
||||
contentComponent={stepContent}
|
||||
backgroundImage={resultsBackgroundImage}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue