finished implementing the custom grain functionality on the grains page and the basic desktop view, and also am now using permissions to disable the buttons ro add/update/remove
This commit is contained in:
parent
2f8897d8ed
commit
586c971795
4 changed files with 244 additions and 21 deletions
|
|
@ -30,6 +30,7 @@ export default function CustomGrainForm(props: Props) {
|
|||
setConstantC(grainSettings.c.toString())
|
||||
setKgPerBushel(grainSettings.kgPerBushel.toString())
|
||||
setBushelsPerTonne(grainSettings.bushelsPerTonne.toString())
|
||||
setNewGrainSettings(grainSettings)
|
||||
}
|
||||
},[grainSettings])
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,144 @@
|
|||
import { useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import PageContainer from "./PageContainer";
|
||||
import CustomGrainForm from "grain/CustomGrainForm";
|
||||
import { Box, Button, Grid2, Typography } from "@mui/material";
|
||||
import { Box, Button, DialogActions, DialogContent, DialogTitle, Grid2, Typography } from "@mui/material";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import ButtonGroup from "common/ButtonGroup";
|
||||
import { useMobile } from "hooks";
|
||||
import { useMobile, useSnackbar, useUserAPI } from "hooks";
|
||||
import { useGrainAPI } from "providers/pond/grainAPI";
|
||||
import ResponsiveTable from "common/ResponsiveTable";
|
||||
import { GrainExtension } from "grain";
|
||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||
import { useGlobalState } from "providers";
|
||||
import { Scope } from "models";
|
||||
|
||||
export default function Grains() {
|
||||
const [currentCustomGrain, setCurrentCustomGrain] = useState<pond.GrainSettings>()
|
||||
const [formValid, setFormValid] = useState(false)
|
||||
const [selectedGrain, setSelectedGrain] = useState<pond.GrainObject | undefined>()
|
||||
const [displayCustom, setDisplayCustom] = useState(false)
|
||||
const [grainTableData, setGrainTableData] = useState()
|
||||
const { openSnack } = useSnackbar()
|
||||
const [tableSize, setTableSize] = useState(5)
|
||||
const [tablePage, setTablePage] = useState(0)
|
||||
const [tableTotal, setTableTotal] = useState(0)
|
||||
const grainAPI = useGrainAPI()
|
||||
const userAPI = useUserAPI()
|
||||
const [{as, user}] = useGlobalState();
|
||||
const [permissions, setPermissions] = useState<pond.Permission[]>([])
|
||||
const [openRemoveConfirmation, setOpenRemoveConfirmation] = useState(false)
|
||||
const [openUpdateConfirmation, setOpenUpdateConfirmation] = useState(false)
|
||||
const [grainObjectTableData, setGrainObjectTableData] = useState<pond.GrainObject[]>([])
|
||||
const [supportedGrainTableData, setSupportedGrainTableData] = useState<GrainExtension[]>([])
|
||||
const isMobile = useMobile()
|
||||
|
||||
//function to load the first set of custom grains
|
||||
const loadCustomGrain = () => {}
|
||||
const loadCustomGrain = useCallback(() => {
|
||||
grainAPI.listGrains(tableSize, tablePage * tableSize, "asc", "name").then(resp => {
|
||||
setGrainObjectTableData(resp.data.grains)
|
||||
setTableTotal(resp.data.total)
|
||||
}).catch(err => {
|
||||
openSnack("There was an issue loading your custom grains")
|
||||
})
|
||||
},[tableSize, tablePage])
|
||||
|
||||
useEffect(() => {
|
||||
if(displayCustom){
|
||||
loadCustomGrain()
|
||||
}
|
||||
//if the user is viewing as a team get their permissions to the team, if they are not then we will get their permission to the grain typ individually when a type is selected
|
||||
if(as){
|
||||
userAPI.getUser(user.id(), { key: as, kind: "team" } as Scope).then(resp => {
|
||||
setPermissions(resp.permissions);
|
||||
});
|
||||
}
|
||||
},[loadCustomGrain, tableSize, tablePage, displayCustom, as])
|
||||
|
||||
const equationName = (enumVal: number) => {
|
||||
switch(enumVal){
|
||||
case pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST:
|
||||
return "Chung-Pfost"
|
||||
case pond.MoistureEquation.MOISTURE_EQUATION_HALSEY:
|
||||
return "Halsey"
|
||||
case pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON:
|
||||
return "Henderson"
|
||||
case pond.MoistureEquation.MOISTURE_EQUATION_OSWIN:
|
||||
return "Oswin"
|
||||
default:
|
||||
return "None"
|
||||
}
|
||||
}
|
||||
|
||||
//function to update
|
||||
|
||||
//tabs to select supported and custom
|
||||
const grainTab = () => {}
|
||||
|
||||
//table that will display the grains (both for the supported grain and custom for the user)
|
||||
const grainTable = () => {
|
||||
//table that will display the custom grains created by the user
|
||||
const grainObjectTable = () => {
|
||||
return (
|
||||
<ResponsiveTable<pond.GrainObject>
|
||||
rows={grainObjectTableData}
|
||||
onRowClick={(grainObj) => {
|
||||
setCurrentCustomGrain(grainObj.settings ?? pond.GrainSettings.create())
|
||||
setSelectedGrain(grainObj)
|
||||
setFormValid(true)
|
||||
/** if they are viewin as a team leave the permissions alone, if not then use the users permissions to the grain type,
|
||||
* for the moment grain types are not shareable so this will be unused, but this will cover our bases if we want to implement sharing in the future
|
||||
* */
|
||||
if (!as) {
|
||||
userAPI.getUser(user.id(), { key: grainObj.key, kind: "grain" } as Scope).then(resp => {
|
||||
setPermissions(resp.permissions);
|
||||
});
|
||||
}
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
title: "Name",
|
||||
render: row => <Box>
|
||||
<Typography>
|
||||
{row.name}
|
||||
</Typography>
|
||||
</Box>
|
||||
},
|
||||
{
|
||||
title: "Group",
|
||||
render: row => <Box>
|
||||
<Typography>
|
||||
{row.settings?.group}
|
||||
</Typography>
|
||||
</Box>
|
||||
},
|
||||
{
|
||||
title: "Equation",
|
||||
render: row => <Box>
|
||||
<Typography>
|
||||
{equationName(row.settings?.equation ?? 0)}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
]}
|
||||
page={tablePage}
|
||||
pageSize={tableSize}
|
||||
handleRowsPerPageChange={(e) => {
|
||||
setTableSize(e.target.value)
|
||||
}}
|
||||
setPage={(page) => {
|
||||
setTablePage(page)
|
||||
}}
|
||||
total={tableTotal}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
//table that will display the grain extensions provided by us
|
||||
const supportedGrainTable = () => {
|
||||
return (
|
||||
<ResponsiveTable<GrainExtension>
|
||||
rows={supportedGrainTableData}
|
||||
page={tablePage}
|
||||
pageSize={tableSize}
|
||||
handleRowsPerPageChange={() => {}}
|
||||
setPage={() => {}}
|
||||
total={tableTotal}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
//the grain display for supported grain type to show the rest of the data such as what constants are used in the formula
|
||||
|
|
@ -32,11 +148,101 @@ export default function Grains() {
|
|||
)
|
||||
}
|
||||
|
||||
const updateGrain = () => {
|
||||
if(selectedGrain && currentCustomGrain){
|
||||
grainAPI.updateGrain(selectedGrain.key, currentCustomGrain).then(resp => {
|
||||
openSnack("Grain type updated")
|
||||
}).catch(err => {
|
||||
openSnack("There was an issue updating the selected grain type")
|
||||
})
|
||||
}
|
||||
}
|
||||
const updateGrainConfirmation = () => {
|
||||
return (
|
||||
<ResponsiveDialog open={openUpdateConfirmation} onClose={() => {setOpenUpdateConfirmation(false)}}>
|
||||
<DialogTitle>Update Custom Grain</DialogTitle>
|
||||
<DialogContent>
|
||||
Update existing custom grain type?
|
||||
<br/>
|
||||
Note that updating the grain here will not change any bins or components this type was used for, those will retain the old settings.
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="contained" color="primary" onClick={()=>{setOpenUpdateConfirmation(false)}}>Cancel</Button>
|
||||
<Button variant="contained" color="primary" onClick={()=>{updateGrain()}}>Confirm</Button>
|
||||
</DialogActions>
|
||||
</ResponsiveDialog>
|
||||
)
|
||||
}
|
||||
|
||||
const addNewGrain = () => {
|
||||
if(currentCustomGrain){
|
||||
grainAPI.addGrain(currentCustomGrain).then(resp => {
|
||||
//new grain added
|
||||
openSnack("New grain type added")
|
||||
}).catch(err => {
|
||||
openSnack("There was a problem creating the new grain type")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const removeGrain = () => {
|
||||
if(selectedGrain){
|
||||
grainAPI.removeGrain(selectedGrain.key).then(resp => {
|
||||
openSnack("Grain type removed")
|
||||
}).catch(err => {
|
||||
openSnack("There was a problem removing the selected grain type")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const removeConfirmation = () => {
|
||||
return (
|
||||
<ResponsiveDialog open={openRemoveConfirmation} onClose={() => {setOpenRemoveConfirmation(false)}}>
|
||||
<DialogTitle>Remove Custom Grain</DialogTitle>
|
||||
<DialogContent>
|
||||
Remove custom grain type?
|
||||
<br />
|
||||
Note that removing the grain here will not change any bins or components this type was used for, those will retain the old settings.
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="contained" color="primary" onClick={()=>{setOpenRemoveConfirmation(false)}}>Cancel</Button>
|
||||
<Button variant="contained" color="primary" onClick={()=>{removeGrain()}}>Confirm</Button>
|
||||
</DialogActions>
|
||||
</ResponsiveDialog>
|
||||
)
|
||||
}
|
||||
|
||||
const customGrainActions = () => {
|
||||
return (
|
||||
<Box display="flex" justifyContent="space-between">
|
||||
<Box>
|
||||
{selectedGrain &&
|
||||
<Button disabled={!permissions.includes(pond.Permission.PERMISSION_WRITE)} variant="contained" color="error" onClick={() => {setOpenRemoveConfirmation(true)}}>Remove Grain</Button>
|
||||
}
|
||||
</Box>
|
||||
<Box>
|
||||
{selectedGrain &&
|
||||
<Button sx={{marginRight: 1}} onClick={() => setOpenUpdateConfirmation(true)} disabled={!formValid || !permissions.includes(pond.Permission.PERMISSION_WRITE)} variant="contained" color="primary">Update</Button>
|
||||
}
|
||||
<Button onClick={() => addNewGrain()} disabled={!formValid || !permissions.includes(pond.Permission.PERMISSION_WRITE)} variant="contained" color="primary">Save New</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
//the grain display for custom grain the user has defined
|
||||
const customGrainDisplay = () => {
|
||||
return (
|
||||
<Box padding={2}>
|
||||
<CustomGrainForm grainSettings={currentCustomGrain} onGrainSettingsChange={()=>{}}/>
|
||||
<Box>
|
||||
<CustomGrainForm
|
||||
grainSettings={currentCustomGrain}
|
||||
onGrainSettingsChange={(newSettings, formValid)=>{
|
||||
setCurrentCustomGrain(newSettings)
|
||||
setFormValid(formValid)
|
||||
}}
|
||||
/>
|
||||
{customGrainActions()}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
|
@ -44,10 +250,10 @@ export default function Grains() {
|
|||
const desktopView = () => {
|
||||
return (
|
||||
<Grid2 container>
|
||||
<Grid2 size={7}>
|
||||
|
||||
<Grid2 size={7} padding={2}>
|
||||
{displayCustom ? grainObjectTable() : supportedGrainTable()}
|
||||
</Grid2>
|
||||
<Grid2 size={5}>
|
||||
<Grid2 size={5} padding={2}>
|
||||
{displayCustom ? customGrainDisplay() : supportedDisplay()}
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
|
|
@ -73,20 +279,22 @@ export default function Grains() {
|
|||
title: "Supported",
|
||||
function: () => {
|
||||
setDisplayCustom(false)
|
||||
setTablePage(0)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Custom",
|
||||
function: () => {
|
||||
setDisplayCustom(true)
|
||||
setTablePage(0)
|
||||
}
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</Box>
|
||||
{!isMobile ? desktopView() : mobileView()}
|
||||
{/* <Button onClick={() => {setCurrentCustomGrain(pond.GrainSettings.create({name: "grain one"}))}}>CG1</Button>
|
||||
<Button onClick={() => {setCurrentCustomGrain(pond.GrainSettings.create({name: "grain two"}))}}>CG2</Button> */}
|
||||
{!isMobile ? desktopView() : mobileView()}
|
||||
{updateGrainConfirmation()}
|
||||
{removeConfirmation()}
|
||||
</PageContainer>
|
||||
)
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ export interface IGrainInterface {
|
|||
types?: string[],
|
||||
otherTeam?: string,
|
||||
) => Promise<AxiosResponse<pond.ListGrainsResponse>>;
|
||||
updateGrain: (key: string, settings: pond.GrainSettings, otherTeam?: string) => Promise<AxiosResponse<pond.UpdateGrainResponse>>
|
||||
removeGrain: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.RemoveGrainResponse>>;
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +32,7 @@ interface Props {}
|
|||
|
||||
export default function GrainProvider(props: PropsWithChildren<Props>) {
|
||||
const { children } = props;
|
||||
const { get, del, post } = useHTTP();
|
||||
const { get, del, post, put } = useHTTP();
|
||||
const [{ as }] = useGlobalState();
|
||||
|
||||
//add
|
||||
|
|
@ -79,7 +80,6 @@ export default function GrainProvider(props: PropsWithChildren<Props>) {
|
|||
get<pond.ListGrainsResponse>(
|
||||
pondURL(
|
||||
"/grains?limit=" +
|
||||
"?limit=" +
|
||||
limit +
|
||||
"&offset=" +
|
||||
offset +
|
||||
|
|
@ -98,6 +98,19 @@ export default function GrainProvider(props: PropsWithChildren<Props>) {
|
|||
})
|
||||
})
|
||||
};
|
||||
|
||||
//update
|
||||
const updateGrain = (key: string, settings: pond.GrainSettings, otherTeam?: string) => {
|
||||
const view = otherTeam ? otherTeam : as
|
||||
if (view) {
|
||||
return put<pond.UpdateGrainResponse>(
|
||||
pondURL("/grains/"+ key + "?&as=" + view),
|
||||
settings
|
||||
);
|
||||
}
|
||||
return put<pond.UpdateGrainResponse>(pondURL("/grains/" + key), settings);
|
||||
}
|
||||
|
||||
//remove
|
||||
const removeGrain = (key: string, otherTeam?: string) => {
|
||||
const view = otherTeam ? otherTeam : as
|
||||
|
|
@ -113,6 +126,7 @@ export default function GrainProvider(props: PropsWithChildren<Props>) {
|
|||
addGrain,
|
||||
getGrain,
|
||||
listGrains,
|
||||
updateGrain,
|
||||
removeGrain
|
||||
}}>
|
||||
{children}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue