added the harvest plan stuff for the map and field drawer

This commit is contained in:
csawatzky 2025-03-28 10:51:48 -06:00
parent a8e7ae1041
commit e2e061151b
11 changed files with 1610 additions and 36 deletions

View file

@ -0,0 +1,108 @@
import {
Button,
DialogActions,
DialogContent,
DialogTitle,
MenuItem,
TextField
} from "@mui/material";
import ResponsiveDialog from "common/ResponsiveDialog";
import { Field, HarvestPlan, /*Task*/ } from "models";
import moment from "moment";
import { pond } from "protobuf-ts/pond";
import { useHarvestPlanAPI/*, useTaskAPI*/ } from "providers";
import { useCallback, useEffect, useState } from "react";
interface Props {
open: boolean;
close: () => void;
fields: Field[];
plan: HarvestPlan;
}
export default function DuplicateHarvestPlan(props: Props) {
const { open, close, fields, plan } = props;
const [newFieldIndex, setNewFieldIndex] = useState(0);
//const [planTasks, setPlanTasks] = useState<Task[]>([]);
const [title, setTitle] = useState("");
const harvestPlanAPI = useHarvestPlanAPI();
//const taskAPI = useTaskAPI();
const [ready, setReady] = useState(false);
// const loadTasks = useCallback(() => {
// taskAPI.listTasks(50, 0, "asc", "start", plan.key()).then(resp => {
// setPlanTasks(resp.data.tasks.map(t => Task.any(t)));
// setReady(true);
// });
// }, [taskAPI, plan]);
// useEffect(() => {
// loadTasks();
// }, [loadTasks]);
const duplicate = () => {
let planSettings = HarvestPlan.clone(plan).settings;
planSettings.field = fields[newFieldIndex].key();
planSettings.createDate = moment.now();
if (title !== "") {
planSettings.title = title;
}
harvestPlanAPI.addHarvestPlan(planSettings).then(resp => {
// let tasks = planTasks;
// tasks.forEach(task => {
// task.settings.objectKey = resp.data.harvestPlan;
// taskAPI.addTask(task.settings);
// });
});
close();
};
return (
<ResponsiveDialog open={open} onClose={close}>
<DialogTitle>Duplicate Crop Plan</DialogTitle>
<DialogContent>
<TextField
margin="normal"
fullWidth
select
label="Field"
value={newFieldIndex}
onChange={e => setNewFieldIndex(+e.target.value)}
color="primary">
{fields.map((option, i) => (
<MenuItem key={option.key()} value={i}>
{option.fieldName()}
</MenuItem>
))}
</TextField>
<TextField
fullWidth
margin="normal"
type="text"
label="Title"
value={title}
helperText={"Leave blank to use the same title*"}
onChange={e => setTitle(e.target.value)}
/>
</DialogContent>
<DialogActions>
<Button
onClick={close}
variant="contained"
style={{ color: "black", backgroundColor: "red" }}>
Cancel
</Button>
<Button
onClick={duplicate}
variant="contained"
color="primary"
disabled={
!ready ||
(fields[newFieldIndex] &&
!fields[newFieldIndex].permissions.includes(pond.Permission.PERMISSION_WRITE))
}>
Duplicate
</Button>
</DialogActions>
</ResponsiveDialog>
);
}

View file

@ -0,0 +1,235 @@
import {
Box,
Button,
IconButton,
ListItemIcon,
ListItemText,
Menu,
MenuItem,
Theme
} from "@mui/material";
import MoreIcon from "@mui/icons-material/MoreVert";
import ShareObjectIcon from "@mui/icons-material/Share";
import ObjectUsersIcon from "@mui/icons-material/AccountCircle";
import ObjectTeamsIcon from "@mui/icons-material/SupervisedUserCircle";
import { pond } from "protobuf-ts/pond";
import React, { useState } from "react";
import ObjectUsers from "user/ObjectUsers";
import ShareObject from "user/ShareObject";
import { isOffline } from "utils/environment";
import ObjectTeams from "teams/ObjectTeams";
import { planScope, HarvestPlan, Field } from "models";
import HarvestSettings from "./HarvestSettings";
import DuplicateHarvestPlan from "./DuplicateHarvestPlan";
import { Edit } from "@mui/icons-material";
import { makeStyles } from "@mui/styles";
import { blue } from "@mui/material/colors";
const useStyles = makeStyles((theme: Theme) => ({
shareIcon: {
color: blue["500"],
"&:hover": {
color: blue["600"]
}
},
removeIcon: {
color: "var(--status-alert)"
},
red: {
color: "var(--status-alert)"
}
}));
interface Props {
plan: HarvestPlan;
planField: Field;
fieldList: Field[];
permissions: pond.Permission[];
refreshCallback: (updatedPlan?: HarvestPlan) => void;
hideNew?: boolean;
}
interface OpenState {
share: boolean;
users: boolean;
teams: boolean;
settings: boolean;
removeSelf: boolean;
duplicate: boolean;
}
export default function HarvestPlanActions(props: Props) {
const classes = useStyles();
const { plan, planField, fieldList, permissions, refreshCallback, hideNew } = props;
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const [openState, setOpenState] = useState<OpenState>({
share: false,
users: false,
teams: false,
settings: false,
removeSelf: false,
duplicate: false
});
const [updatePlan, setUpdatePlan] = useState(false);
const groupMenu = () => {
const canShare = permissions.includes(pond.Permission.PERMISSION_SHARE);
const canManageUsers = permissions.includes(pond.Permission.PERMISSION_USERS);
return (
<Menu
id="groupMenu"
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={() => setAnchorEl(null)}
keepMounted
disableAutoFocusItem>
{!isOffline() &&
planField.permissions.includes(pond.Permission.PERMISSION_WRITE) &&
!hideNew && (
<MenuItem
dense
onClick={() => {
setUpdatePlan(false);
setOpenState({ ...openState, settings: true });
setAnchorEl(null);
}}>
<ListItemIcon></ListItemIcon>
<ListItemText primary="New Plan" />
</MenuItem>
)}
{!isOffline() && planField.permissions.includes(pond.Permission.PERMISSION_WRITE) && (
<MenuItem
dense
onClick={() => {
setOpenState({ ...openState, duplicate: true });
setAnchorEl(null);
}}>
<ListItemIcon></ListItemIcon>
<ListItemText primary="Duplicate Plan" />
</MenuItem>
)}
{!isOffline() && canShare && (
<MenuItem
dense
onClick={() => {
setOpenState({ ...openState, share: true });
setAnchorEl(null);
}}>
<ListItemIcon>
<ShareObjectIcon className={classes.shareIcon} />
</ListItemIcon>
<ListItemText primary="Share" />
</MenuItem>
)}
{!isOffline() && canManageUsers && (
<MenuItem
dense
onClick={() => {
setOpenState({ ...openState, users: true });
setAnchorEl(null);
}}>
<ListItemIcon>
<ObjectUsersIcon />
</ListItemIcon>
<ListItemText primary="Users" />
</MenuItem>
)}
{!isOffline() && canManageUsers && (
<MenuItem
dense
onClick={() => {
setOpenState({ ...openState, teams: true });
setAnchorEl(null);
}}>
<ListItemIcon>
<ObjectTeamsIcon />
</ListItemIcon>
<ListItemText primary="Teams" />
</MenuItem>
)}
</Menu>
);
};
const dialogs = () => {
const key = plan.key();
const label = plan.settings.title;
return (
<React.Fragment>
<HarvestSettings
field={planField}
update={updatePlan}
open={openState.settings}
plan={plan.key() !== "" ? plan : undefined}
close={(refresh, updatedPlan) => {
setOpenState({ ...openState, settings: false });
if (refresh) {
refreshCallback(updatedPlan);
}
}}
/>
<DuplicateHarvestPlan
open={openState.duplicate}
close={() => {
setOpenState({ ...openState, duplicate: false });
refreshCallback();
}}
fields={fieldList}
plan={plan}
/>
<ShareObject
scope={planScope(key)}
label={label}
permissions={permissions}
isDialogOpen={openState.share}
closeDialogCallback={() => setOpenState({ ...openState, share: false })}
/>
<ObjectUsers
scope={planScope(key)}
label={label}
permissions={permissions}
isDialogOpen={openState.users}
closeDialogCallback={() => setOpenState({ ...openState, users: false })}
refreshCallback={refreshCallback}
/>
<ObjectTeams
scope={planScope(key)}
label="Teams"
permissions={permissions}
isDialogOpen={openState.teams}
refreshCallback={refreshCallback}
closeDialogCallback={() => setOpenState({ ...openState, teams: false })}
/>
</React.Fragment>
);
};
return (
<React.Fragment>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
{plan.key() !== "" && (
<Button
variant="contained"
color="primary"
onClick={() => {
setUpdatePlan(true);
setOpenState({ ...openState, settings: true });
}}>
<Edit /> Edit or Add Activity
</Button>
)}
<IconButton
aria-owns={anchorEl ? "groupMenu" : undefined}
aria-haspopup="true"
onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
setAnchorEl(event.currentTarget)
}>
<MoreIcon />
</IconButton>
</Box>
{groupMenu()}
{dialogs()}
</React.Fragment>
);
}

View file

@ -0,0 +1,209 @@
import {
Box,
Grid2 as Grid,
Theme,
Typography,
IconButton,
LinearProgress,
Drawer
} from "@mui/material";
import { Notes } from "@mui/icons-material";
import GrainDescriber from "grain/GrainDescriber";
import { Field, HarvestPlan } from "models";
import React, { useState } from "react";
import { getThemeType } from "theme";
import Chat from "chat/Chat";
import { pond } from "protobuf-ts/pond";
import { useMobile } from "hooks";
import HarvestPlanActions from "./HarvestPlanActions";
import { makeStyles } from "@mui/styles";
interface Props {
plan: HarvestPlan;
permissions: pond.Permission[];
planField: Field;
loading: boolean;
fieldList: Field[];
changePlan: (updatedPlan?: HarvestPlan) => void;
}
const useStyles = makeStyles((theme: Theme) => ({
dark: {
backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(50, 50, 50)",
padding: 5
},
light: {
backgroundColor: getThemeType() === "light" ? "rgb(235, 235, 235)" : "rgb(60, 60, 60)",
padding: 5
},
avatar: {
color: getThemeType() === "light" ? theme.palette.common.black : theme.palette.common.white,
backgroundColor: "transparent",
width: theme.spacing(5),
height: theme.spacing(5),
border: "1px solid",
borderColor: theme.palette.divider
}
}));
export default function HarvestPlanDisplay(props: Props) {
const { plan, loading, planField, fieldList, changePlan, permissions } = props;
const classes = useStyles();
const [openNote, setOpenNote] = useState(false);
const isMobile = useMobile();
const planTable = () => {
return (
<React.Fragment>
<Grid container direction="column">
<Grid className={classes.dark}>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant="subtitle1">Break Even Yield:</Typography>
<Typography variant="subtitle1">
{(
(plan.totalEquipmentCost() + plan.totalMaterialCost()) /
plan.bushelPrice()
).toFixed(2)}{" "}
BU
</Typography>
</Box>
</Grid>
<Grid className={classes.light}>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant="subtitle1">Break Even Sales Price</Typography>
<Typography variant="subtitle1">
$
{(
(plan.totalEquipmentCost() + plan.totalMaterialCost()) /
plan.yieldTarget()
).toFixed(2)}
</Typography>
</Box>
</Grid>
</Grid>
<Grid container direction="column" style={{ marginTop: 20 }}>
<Grid className={classes.dark}>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant="subtitle1">Harvest Year:</Typography>
<Typography variant="subtitle1">{plan.harvestYear()}</Typography>
</Box>
</Grid>
<Grid className={classes.light}>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant="subtitle1">Title:</Typography>
<Typography variant="subtitle1">{plan.settings.title}</Typography>
</Box>
</Grid>
<Grid className={classes.dark}>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant="subtitle1">Grain:</Typography>
<Typography variant="subtitle1">{GrainDescriber(plan.cropType()).name}</Typography>
</Box>
</Grid>
<Grid className={classes.light}>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant="subtitle1">Variant:</Typography>
<Typography variant="subtitle1">{plan.grainType()}</Typography>
</Box>
</Grid>
<Grid className={classes.dark}>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant="subtitle1">Bushel Price:</Typography>
<Typography variant="subtitle1">${plan.bushelPrice()}</Typography>
</Box>
</Grid>
<Grid className={classes.light}>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant="subtitle1">Yield Target:</Typography>
<Typography variant="subtitle1">{plan.yieldTarget()}</Typography>
</Box>
</Grid>
<Grid className={classes.dark}>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant="subtitle1">Total Cost (acre):</Typography>
<Typography variant="subtitle1">
${(plan.totalEquipmentCost() + plan.totalMaterialCost()).toFixed(2)}
</Typography>
</Box>
</Grid>
<Grid className={classes.light}>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant="subtitle1">Total Cost:</Typography>
<Typography variant="subtitle1">
$
{(
(plan.totalEquipmentCost() + plan.totalMaterialCost()) *
planField.acres()
).toFixed(2)}
</Typography>
</Box>
</Grid>
</Grid>
</React.Fragment>
);
};
const noteDrawer = () => {
return (
<Drawer
anchor={isMobile ? "bottom" : "right"}
open={openNote}
onClose={() => setOpenNote(false)}>
<Box height={isMobile ? "50vh" : "100vh"} padding={2}>
<Typography style={{ fontWeight: 650 }}>Notes</Typography>
<Chat type={pond.NoteType.NOTE_TYPE_HARVEST_PLAN} objectKey={plan.key()} />
</Box>
</Drawer>
);
};
return (
<React.Fragment>
{loading ? (
<Box paddingTop="20px">
<LinearProgress color="primary" />
</Box>
) : (
<React.Fragment>
<IconButton
disabled={plan.key() === ""}
className={classes.avatar}
onClick={() => setOpenNote(true)}>
<Notes />
</IconButton>
<Box style={{ display: "flex", justifyContent: "space-between" }}>
<Typography
variant="h5"
style={{ fontWeight: 700, marginTop: "auto", marginBottom: "auto" }}>
Crop Plan{plan.key() !== "" ? " - " + plan.settings.title : " - None Found"}
</Typography>
{!isMobile && permissions.includes(pond.Permission.PERMISSION_WRITE) && (
<HarvestPlanActions
planField={planField}
fieldList={fieldList}
plan={plan}
permissions={permissions}
refreshCallback={updatedPlan => {
changePlan(updatedPlan);
}} //possibly need to re-load plan here
/>
)}
</Box>
{isMobile && permissions.includes(pond.Permission.PERMISSION_WRITE) && (
<HarvestPlanActions
planField={planField}
fieldList={fieldList}
plan={plan}
permissions={permissions}
refreshCallback={updatedPlan => {
changePlan(updatedPlan);
}} //possibly need to re-load plan here
/>
)}
{plan.key() !== "" && planTable()}
</React.Fragment>
)}
{noteDrawer()}
</React.Fragment>
);
}

View file

@ -0,0 +1,728 @@
import {
Box,
Button,
DialogActions,
DialogContent,
DialogTitle,
Grid2 as Grid,
InputAdornment,
MenuItem,
Tab,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
Tabs,
TextField,
Theme,
Tooltip,
Typography
} from "@mui/material";
import { makeStyles } from "@mui/styles";
import ResponsiveDialog from "common/ResponsiveDialog";
import { useMobile, useSnackbar } from "hooks";
import { Field, HarvestPlan/*, Task*/ } from "models";
import moment from "moment";
import { pond } from "protobuf-ts/pond";
import { useHarvestPlanAPI/*, useTaskAPI*/ } from "providers";
import React, { useCallback, useEffect, useState } from "react";
//import TaskSettings from "tasks/TaskSettings";
interface Props {
open: boolean;
close: (reload?: boolean, updatedPlan?: HarvestPlan) => void;
field: Field;
update?: boolean;
plan?: HarvestPlan;
}
const cropOptions = [
{
value: 2,
label: "Barley"
},
{
value: 4,
label: "Canola"
},
{
value: 5,
label: "Corn"
},
{
value: 6,
label: "Oats"
},
{
value: 7,
label: "Peanuts"
},
{
value: 8,
label: "Rapeseed"
},
{
value: 9,
label: "Long Grain Rice"
},
{
value: 10,
label: "Medium Grain Rice"
},
{
value: 11,
label: "Short Grain Rice"
},
{
value: 12,
label: "Sorghum"
},
{
value: 13,
label: "Soybeans"
},
{
value: 14,
label: "Sunflower"
},
{
value: 3,
label: "Buckwheat"
},
{
value: 15,
label: "Durum Wheat"
},
{
value: 16,
label: "Hard Red Wheat"
},
{
value: 17,
label: "Unretted Flax"
},
{
value: 18,
label: "Dew Retted Flax"
},
{
value: 19,
label: "Yellow Peas"
},
{
value: 20,
label: "Robin Lentils"
},
{
value: 21,
label: "Redberry Lentils"
},
{
value: 22,
label: "Blaze Lentils"
}
];
const useStyles = makeStyles((theme: Theme) => ({
stepper: {
padding: theme.spacing(0.5)
},
secondaryColor: {
color: theme.palette.secondary.main
},
textSecondaryColor: {
color: theme.palette.text.secondary
},
bottomSpacing: {
marginBottom: theme.spacing(1)
},
tabs: {
width: "100%",
boxSizing: "border-box",
flexShrink: 1
},
tabSmall: {
width: "100%",
boxSizing: "border-box",
flexShrink: 1,
minWidth: "48px"
},
tab: {
width: "16%",
minWidth: "16%"
},
buttonSpacing: {
margin: 5
}
}));
const steps = ["Pre-Seeding", "Seeding", "Post-Seeding", "Harvest", "Fall"];
export default function HarvestSettings(props: Props) {
const { open, plan, close, field, update } = props;
const [planKey, setPlanKey] = useState<string>();
const [newPlan, setNewPlan] = useState(HarvestPlan.create());
const [activeStep, setActiveStep] = useState(0);
const isMobile = useMobile();
const classes = useStyles();
//const [planTasks, setPlanTasks] = useState<Task[]>([]);
//const taskAPI = useTaskAPI();
const harvestPlanAPI = useHarvestPlanAPI();
const [title, setTitle] = useState("");
const [cropType, setCropType] = useState(0);
const [customCropType, setCustomCropType] = useState("");
const [useCustom, setUseCustom] = useState(false);
const [variety, setVariety] = useState("");
const [harvestYear, setHarvestYear] = useState(new Date().getFullYear());
const [targetYield, setTargetYield] = useState(0);
const [price, setPrice] = useState("");
const [newTaskDialog, setNewTaskDialog] = useState(false);
const [type, setType] = useState("");
//const [taskToEdit, setTaskToEdit] = useState<Task>();
const { openSnack } = useSnackbar();
const [deleteOpen, setDeleteOpen] = useState(false);
// const loadTasks = useCallback(() => {
// if (planKey) {
// taskAPI.getMultiTasks([planKey]).then(resp => {
// setPlanTasks(resp.data.tasks.map(t => Task.any(t)));
// });
// }
// }, [taskAPI, planKey]);
// useEffect(() => {
// loadTasks();
// }, [loadTasks]);
useEffect(() => {
if (!plan || (plan && plan.permissions.includes(pond.Permission.PERMISSION_WRITE))) {
setActiveStep(0);
} else {
setActiveStep(1);
}
setPlanKey(undefined);
setTitle("");
setVariety("");
setHarvestYear(new Date().getFullYear());
setTargetYield(0);
setPrice("");
if (update && plan) {
setPlanKey(plan.key());
setTitle(plan.settings.title);
setCropType(plan.cropType());
setCustomCropType(plan.customCropType());
setVariety(plan.grainType());
setHarvestYear(plan.harvestYear());
setTargetYield(plan.yieldTarget());
setPrice(plan.settings.bushelPrice.toFixed(2).toString());
} else {
setCropType(field.crop());
setCustomCropType(field.customType());
setUseCustom(field.crop() === pond.Grain.GRAIN_CUSTOM);
}
}, [plan, field, update]);
const closeDialog = (reload?: boolean, updatedPlan?: HarvestPlan) => {
close(reload, updatedPlan);
};
// const showTasks = (type: string) => {
// let tasks: Task[] = [];
// let costTotal = 0;
// let secondaryCostTotal = 0;
// planTasks.forEach(task => {
// if (task.settings.type === type) {
// tasks.push(task);
// costTotal += task.cost();
// secondaryCostTotal += task.secondaryCost();
// }
// });
// let frag = (
// <React.Fragment>
// <Table>
// <TableHead>
// <TableRow>
// <TableCell>Title</TableCell>
// <TableCell>Description</TableCell>
// {!isMobile && <TableCell>Material Cost(acre)</TableCell>}
// {!isMobile && <TableCell>Equipment Cost(acre)</TableCell>}
// <TableCell>Total(acre)</TableCell>
// {!isMobile && <TableCell>Start -End</TableCell>}
// <TableCell>Edit</TableCell>
// </TableRow>
// </TableHead>
// <TableBody>
// {tasks.map((task, i) => (
// <TableRow key={i}>
// <TableCell>{task.title()}</TableCell>
// <TableCell>{task.description()}</TableCell>
// {!isMobile && <TableCell>${task.cost().toFixed(2)}</TableCell>}
// {!isMobile && <TableCell>${task.secondaryCost().toFixed(2)}</TableCell>}
// <TableCell>
// ${(Math.round((task.cost() + task.secondaryCost()) * 100) / 100).toFixed(2)}
// </TableCell>
// {!isMobile && (
// <TableCell>
// {task.start()} {task.end()}
// </TableCell>
// )}
// <TableCell>
// <Button
// color="primary"
// onClick={() => {
// setTaskToEdit(task);
// setNewTaskDialog(true);
// }}>
// Edit
// </Button>
// </TableCell>
// </TableRow>
// ))}
// </TableBody>
// </Table>
// <Box>
// <Typography>
// Total: $
// {(Math.round((costTotal + secondaryCostTotal) * field.acres() * 100) / 100).toFixed(2)}
// </Typography>
// </Box>
// </React.Fragment>
// );
// return frag;
// };
const savePlan = () => {
let newPlanSettings = pond.HarvestPlanSettings.create({
title: title,
field: field.key(),
createDate: moment.now(),
cropType: cropType,
grainType: variety,
harvestYear: harvestYear,
yieldTarget: targetYield,
bushelPrice: !isNaN(parseFloat(price)) ? Math.round(parseFloat(price) * 100) / 100 : 0
});
setNewPlan(HarvestPlan.create(pond.HarvestPlan.fromObject({ settings: newPlanSettings })));
harvestPlanAPI.addHarvestPlan(newPlanSettings).then(resp => {
setPlanKey(resp.data.harvestPlan);
openSnack("Plan Created");
});
};
const updatePlan = () => {
//material costs per acre
let preseedMatCost = 0;
let seedMatCost = 0;
let postseedMatCost = 0;
let harvestMatCost = 0;
let fallMatCost = 0;
//equipment costs per acre
let preseedEqCost = 0;
let seedEqCost = 0;
let postseedEqCost = 0;
let harvestEqCost = 0;
let fallEqCost = 0;
// planTasks.forEach(task => {
// switch (task.settings.type) {
// case "preseed":
// preseedMatCost += task.cost();
// preseedEqCost += task.secondaryCost();
// break;
// case "seed":
// seedMatCost += task.cost();
// seedEqCost += task.secondaryCost();
// break;
// case "postseed":
// postseedMatCost += task.cost();
// postseedEqCost += task.secondaryCost();
// break;
// case "harvest":
// harvestMatCost += task.cost();
// harvestEqCost += task.secondaryCost();
// break;
// default:
// fallMatCost += task.cost();
// fallEqCost += task.secondaryCost();
// break;
// }
// });
let tempPlan = plan ?? newPlan;
tempPlan.settings.cropType = cropType;
tempPlan.settings.field = field.key();
tempPlan.settings.title = title;
tempPlan.settings.grainType = variety;
tempPlan.settings.harvestYear = harvestYear;
tempPlan.settings.yieldTarget = targetYield;
tempPlan.settings.bushelPrice = !isNaN(parseFloat(price))
? Math.round(parseFloat(price) * 100) / 100
: 0;
tempPlan.settings.preSeedMaterials = preseedMatCost;
tempPlan.settings.preSeedEquipment = preseedEqCost;
tempPlan.settings.seedMaterials = seedMatCost;
tempPlan.settings.seedEquipment = seedEqCost;
tempPlan.settings.postSeedMaterials = postseedMatCost;
tempPlan.settings.postSeedEquipment = postseedEqCost;
tempPlan.settings.harvestMaterials = harvestMatCost;
tempPlan.settings.harvestEquipment = harvestEqCost;
tempPlan.settings.fallMaterials = fallMatCost;
tempPlan.settings.fallEquipment = fallEqCost;
if (planKey) {
harvestPlanAPI
.updateHarvestPlan(planKey, tempPlan.settings)
.then(resp => openSnack("Plan Updated"));
}
closeDialog(true, tempPlan);
};
const deletePlan = () => {
if (planKey) {
harvestPlanAPI.removeHarvestPlan(planKey).then(resp => {
openSnack("Plan Deleted");
});
}
setDeleteOpen(false);
closeDialog(true);
};
const handleNextStep = () => {
setActiveStep(prevStep => prevStep + 1);
};
const handleBack = () => {
setActiveStep(prevActiveStep => prevActiveStep - 1);
};
const stepper = () => {
return (
<Box display="flex" justifyContent="center" width="100%">
<Tabs
value={activeStep}
onChange={(_, value) => setActiveStep(value)}
indicatorColor="primary"
textColor="primary"
variant="fullWidth"
aria-label="bin tabs"
classes={{ root: classes.tabs }}>
<Tab
key={0}
classes={{ root: classes.tab }}
disabled={
!planKey || !(plan && plan.permissions.includes(pond.Permission.PERMISSION_WRITE))
}
label={"General"}
aria-label={"general"}
/>
{steps.map((label, i) => (
<Tab
key={i + 1}
classes={{ root: classes.tab }}
disabled={!planKey}
label={label}
aria-label={label}
/>
))}
</Tabs>
</Box>
);
};
const general = () => {
return (
<Box>
<TextField
fullWidth
margin="normal"
type="text"
label="Title"
value={title}
onChange={e => setTitle(e.target.value)}
/>
{useCustom ? (
<TextField
margin="normal"
fullWidth
label="Crop"
value={customCropType}
onChange={e => setCustomCropType(e.target.value)}
color="primary"
/>
) : (
<TextField
margin="normal"
fullWidth
select
label="Crop"
value={cropType}
onChange={e => setCropType(+e.target.value)}
color="primary">
{cropOptions.map(option => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>
)}
<TextField
fullWidth
margin="normal"
type="text"
label="Variety"
value={variety}
onChange={e => setVariety(e.target.value)}
/>
<TextField
fullWidth
margin="normal"
type="number"
label="Year"
value={harvestYear}
onChange={e => {
!isNaN(+e.target.value) && setHarvestYear(+e.target.value);
}}
/>
<TextField
fullWidth
margin="normal"
type="number"
label="Target Yield per acre"
value={targetYield}
onChange={e => {
!isNaN(+e.target.value) && setTargetYield(+e.target.value);
}}
/>
<TextField
margin="dense"
id="bushPrice"
label="Estimated sale price per bushel"
type="text"
fullWidth
helperText="Must be a valid number*"
value={price}
error={isNaN(+price) && price !== ""}
InputProps={{
startAdornment: <InputAdornment position="start">$</InputAdornment>
}}
onChange={e => {
setPrice(e.target.value);
}}
/>
</Box>
);
};
const preSeed = () => {
return (
<Box textAlign="center">
<Button
color="primary"
onClick={() => {
setType("preseed");
setNewTaskDialog(true);
}}>
Add Crop Activity
</Button>
<Typography>Planned Activities</Typography>
{/* {showTasks("preseed")} */}
</Box>
);
};
const seed = () => {
return (
<Box textAlign="center">
<Button
color="primary"
onClick={() => {
setType("seed");
setNewTaskDialog(true);
}}>
Add Crop Activity
</Button>
<Typography>Planned Activities</Typography>
{/* {showTasks("seed")} */}
</Box>
);
};
const postSeed = () => {
return (
<Box textAlign="center">
<Button
color="primary"
onClick={() => {
setType("postseed");
setNewTaskDialog(true);
}}>
Add Crop Activity
</Button>
<Typography>Planned Activities</Typography>
{/* {showTasks("postseed")} */}
</Box>
);
};
const harvest = () => {
return (
<Box textAlign="center">
<Button
color="primary"
onClick={() => {
setType("harvest");
setNewTaskDialog(true);
}}>
Add Crop Activity
</Button>
<Typography>Planned Activities</Typography>
{/* {showTasks("harvest")} */}
</Box>
);
};
const fall = () => {
return (
<Box textAlign="center">
<Button
color="primary"
onClick={() => {
setType("fall");
setNewTaskDialog(true);
}}>
Add Crop Activity
</Button>
<Typography>Planned Activities</Typography>
{/* {showTasks("fall")} */}
</Box>
);
};
const stepperContent = (step: number) => {
switch (step) {
case 1:
return preSeed();
case 2:
return seed();
case 3:
return postSeed();
case 4:
return harvest();
case 5:
return fall();
default:
return general();
}
};
const deleteDialog = () => {
return (
<ResponsiveDialog open={deleteOpen}>
<DialogContent>
Are you sure you wish to delete plan? This action is irreversible.
</DialogContent>
<DialogActions>
<Button onClick={() => setDeleteOpen(false)}>Cancel</Button>
<Button onClick={deletePlan}>
<Typography color="error">Delete</Typography>
</Button>
</DialogActions>
</ResponsiveDialog>
);
};
return (
<React.Fragment>
<ResponsiveDialog open={open} onClose={() => closeDialog()} maxWidth="lg">
<DialogTitle>Create New Crop Plan</DialogTitle>
<DialogContent>
{stepper()}
{stepperContent(activeStep)}
</DialogContent>
<DialogActions>
<Grid container direction="row">
<Grid>
{planKey && plan && field.permissions.includes(pond.Permission.PERMISSION_WRITE) && (
<Button
variant="contained"
style={{ color: "black", backgroundColor: "red" }}
onClick={() => setDeleteOpen(true)}>
Delete
</Button>
)}
</Grid>
<Grid>
<Button
className={classes.buttonSpacing}
variant="contained"
color="primary"
onClick={() => closeDialog()}>
Cancel
</Button>
{activeStep === 0 && !planKey && (
<React.Fragment>
<Button
className={classes.buttonSpacing}
variant="contained"
onClick={() => {
savePlan();
}}
color="primary">
Create Plan
</Button>
</React.Fragment>
)}
{activeStep > 0 && (
<Button
className={classes.buttonSpacing}
variant="contained"
onClick={handleBack}
color="primary">
Back
</Button>
)}
{activeStep < 5 && (activeStep > 0 || planKey) && (
<Button
className={classes.buttonSpacing}
variant="contained"
onClick={handleNextStep}
color="primary">
Next
</Button>
)}
{(planKey || activeStep > 0) && (
<Tooltip title="Finish Harvest Plan">
<Button
className={classes.buttonSpacing}
variant="contained"
color="primary"
onClick={updatePlan}>
Confirm
</Button>
</Tooltip>
)}
</Grid>
</Grid>
</DialogActions>
</ResponsiveDialog>
{deleteDialog()}
{/* <TaskSettings
task={taskToEdit}
hasCost
costTitle="Material Cost(acres)"
secondaryCostTitle="Equipment Cost(acre)"
objectKey={planKey}
type={type}
open={newTaskDialog}
onClose={r => {
setType("");
setTaskToEdit(undefined);
setNewTaskDialog(false);
if (r) {
loadTasks();
}
}}
/> */}
</React.Fragment>
);
}