352 lines
10 KiB
TypeScript
352 lines
10 KiB
TypeScript
import {
|
|
Avatar,
|
|
Box,
|
|
Button,
|
|
Dialog,
|
|
DialogActions,
|
|
DialogContent,
|
|
DialogTitle,
|
|
Grid2 as Grid,
|
|
InputAdornment,
|
|
MenuItem,
|
|
TextField
|
|
} from "@mui/material";
|
|
import moment from "moment";
|
|
import React, { useState } from "react";
|
|
import { pond } from "protobuf-ts/pond";
|
|
import { useGlobalState, useTaskAPI } from "providers";
|
|
import { useSnackbar, useUserAPI } from "hooks";
|
|
import { useEffect } from "react";
|
|
import { Task, teamScope, User } from "models";
|
|
import ColourPicker from "common/ColourPicker";
|
|
import ResponsiveDialog from "common/ResponsiveDialog";
|
|
|
|
interface Props {
|
|
open: boolean;
|
|
onClose: (reLoad?: boolean) => void;
|
|
markComplete?: boolean;
|
|
startDate?: any;
|
|
task?: Task;
|
|
objectKey?: string;
|
|
type?: string;
|
|
hasCost?: boolean;
|
|
costTitle?: string;
|
|
secondaryCostTitle?: string;
|
|
}
|
|
|
|
export default function TaskSettings(props: Props) {
|
|
const [taskName, setTaskName] = useState("");
|
|
const [startDate, setStartDate] = useState(moment().format("YYYY-MM-DD"));
|
|
const [startTime, setStartTime] = useState("00:00");
|
|
const [endDate, setEndDate] = useState("");
|
|
const [endTime, setEndTime] = useState("00:00");
|
|
const [taskDescription, setTaskDescription] = useState("");
|
|
const [{ user, as }] = useGlobalState();
|
|
const [worker, setWorker] = useState(user.id());
|
|
const [colour, setColour] = useState("");
|
|
const taskAPI = useTaskAPI();
|
|
const { openSnack } = useSnackbar();
|
|
const [cost, setCost] = useState("");
|
|
const [secondaryCost, setSecondaryCost] = useState("");
|
|
const [seedCost, setSeedCost] = useState("");
|
|
const [poundPerAcre, setPoundPerAcre] = useState(0);
|
|
const userAPI = useUserAPI();
|
|
const [users, setUsers] = useState<User[]>([]);
|
|
|
|
useEffect(() => {
|
|
if (props.task) {
|
|
setTaskName(props.task.title());
|
|
setStartDate(props.task.start());
|
|
setStartTime(props.task.startTime());
|
|
setEndDate(props.task.end());
|
|
setEndTime(props.task.endTime());
|
|
setTaskDescription(props.task.description());
|
|
setWorker(props.task.worker());
|
|
setColour(props.task.settings.colour);
|
|
setCost(props.task.cost().toString());
|
|
setSecondaryCost(props.task.secondaryCost().toString());
|
|
}
|
|
if (props.startDate) {
|
|
setStartDate(props.startDate);
|
|
}
|
|
}, [props.startDate, props.task]);
|
|
|
|
useEffect(() => {
|
|
if (as === "") {
|
|
setWorker(user.id());
|
|
setUsers([user]);
|
|
} else {
|
|
userAPI.listObjectUsers(teamScope(as)).then(resp => {
|
|
setUsers(resp.data.users.map((u: pond.User) => User.any(u)));
|
|
});
|
|
}
|
|
}, [as, userAPI, user]);
|
|
|
|
const formComplete = () => {
|
|
if (
|
|
taskName.length < 1 ||
|
|
taskDescription.length < 1 ||
|
|
worker.length < 1 ||
|
|
endDate.length < 1
|
|
) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
//saves new tasks into the database
|
|
const newTask = () => {
|
|
let taskSettings = pond.TaskSettings.create({
|
|
userId: user.id(),
|
|
title: taskName,
|
|
start: startDate,
|
|
startTime: startTime,
|
|
end: endDate,
|
|
endTime: endTime,
|
|
objectKey: props.objectKey ? props.objectKey : user.id(),
|
|
description: taskDescription,
|
|
worker: worker,
|
|
complete: false,
|
|
colour: colour,
|
|
type: props.type,
|
|
cost: !isNaN(parseFloat(cost)) ? Math.round((parseFloat(cost) * 100) / 100) : 0,
|
|
secondaryCost: !isNaN(parseFloat(secondaryCost))
|
|
? Math.round((parseFloat(secondaryCost) * 100) / 100)
|
|
: 0
|
|
});
|
|
|
|
let returnTask = Task.create();
|
|
returnTask.settings = taskSettings;
|
|
|
|
taskAPI
|
|
.addTask(taskSettings, as)
|
|
.then(resp => {
|
|
props.onClose(true);
|
|
})
|
|
.catch(err => {
|
|
openSnack("Failed to add new task");
|
|
});
|
|
props.onClose();
|
|
};
|
|
|
|
const updateTask = () => {
|
|
let task: Task = Task.any(props.task);
|
|
task.settings.title = taskName;
|
|
task.settings.start = startDate;
|
|
task.settings.startTime = startTime;
|
|
task.settings.end = endDate;
|
|
task.settings.endTime = endTime;
|
|
task.settings.description = taskDescription;
|
|
task.settings.worker = worker;
|
|
task.settings.colour = colour;
|
|
task.settings.cost = !isNaN(parseFloat(cost)) ? Math.round(parseFloat(cost) * 100) / 100 : 0;
|
|
task.settings.secondaryCost = !isNaN(parseFloat(secondaryCost))
|
|
? Math.round(parseFloat(secondaryCost) * 100) / 100
|
|
: 0;
|
|
|
|
taskAPI
|
|
.updateTask(task.key, task.settings, undefined, as)
|
|
.then(resp => {
|
|
props.onClose(true);
|
|
})
|
|
.catch(err => {
|
|
openSnack("Failed to update task");
|
|
});
|
|
};
|
|
|
|
const closeDialog = () => {
|
|
props.onClose();
|
|
};
|
|
|
|
return (
|
|
<ResponsiveDialog open={props.open} onClose={closeDialog}>
|
|
<DialogTitle id="form-dialog-title">New Task</DialogTitle>
|
|
<DialogContent>
|
|
<TextField
|
|
autoFocus
|
|
margin="dense"
|
|
id="name"
|
|
label="Task Title"
|
|
type="text"
|
|
fullWidth
|
|
value={taskName}
|
|
onChange={e => setTaskName(e.target.value)}
|
|
/>
|
|
<TextField
|
|
margin="dense"
|
|
id="description"
|
|
label="Task Description"
|
|
type="text"
|
|
fullWidth
|
|
multiline
|
|
value={taskDescription}
|
|
onChange={e => setTaskDescription(e.target.value)}
|
|
/>
|
|
<TextField
|
|
disabled={as === ""}
|
|
margin="dense"
|
|
id="worker"
|
|
label="Assigned Worker"
|
|
select
|
|
fullWidth
|
|
value={worker}
|
|
onChange={e => setWorker(e.target.value)}>
|
|
{users.map(u => (
|
|
<MenuItem key={u.id()} value={u.id()}>
|
|
<Grid container direction="row" alignItems="center">
|
|
<Grid>
|
|
<Avatar
|
|
alt={u.name()}
|
|
src={
|
|
u.settings.avatar && u.settings.avatar !== "" ? u.settings.avatar : undefined
|
|
}
|
|
/>
|
|
</Grid>
|
|
<Grid>
|
|
<Box marginLeft={2}>{u.name()}</Box>
|
|
</Grid>
|
|
</Grid>
|
|
</MenuItem>
|
|
))}
|
|
</TextField>
|
|
|
|
{props.type === "seed" && (
|
|
<React.Fragment>
|
|
<TextField
|
|
style={{ width: "45%" }}
|
|
margin="normal"
|
|
id="costPerPound"
|
|
label="Seed Cost Per Pound"
|
|
type="text"
|
|
helperText="Must be a valid number"
|
|
value={seedCost}
|
|
error={isNaN(+seedCost) && seedCost !== ""}
|
|
InputProps={{
|
|
startAdornment: <InputAdornment position="start">$</InputAdornment>,
|
|
endAdornment: <InputAdornment position="end">/Lb</InputAdornment>
|
|
}}
|
|
onChange={e => {
|
|
setSeedCost(e.target.value);
|
|
setCost((parseFloat(e.target.value) * poundPerAcre).toString());
|
|
}}
|
|
/>
|
|
<TextField
|
|
style={{ width: "45%", marginLeft: "10%" }}
|
|
margin="normal"
|
|
id="applicationRate"
|
|
label="Application Rate"
|
|
type="number"
|
|
value={poundPerAcre}
|
|
InputProps={{
|
|
endAdornment: <InputAdornment position="end">Lb/Acre</InputAdornment>
|
|
}}
|
|
onChange={e => {
|
|
setPoundPerAcre(+e.target.value);
|
|
setCost((parseFloat(seedCost) * +e.target.value).toString());
|
|
}}
|
|
/>
|
|
</React.Fragment>
|
|
)}
|
|
{props.hasCost && (
|
|
<TextField
|
|
margin="dense"
|
|
id="cost"
|
|
label={props.costTitle ? props.costTitle : "Cost"}
|
|
type="text"
|
|
fullWidth
|
|
helperText="Must be a valid number"
|
|
value={cost}
|
|
error={isNaN(+cost) && cost !== ""}
|
|
InputProps={{
|
|
startAdornment: <InputAdornment position="start">$</InputAdornment>
|
|
}}
|
|
onChange={e => {
|
|
setCost(e.target.value);
|
|
}}
|
|
/>
|
|
)}
|
|
{props.hasCost && (
|
|
<TextField
|
|
margin="dense"
|
|
id="secondaryCost"
|
|
label={props.secondaryCostTitle ? props.secondaryCostTitle : "Secondary Cost"}
|
|
type="text"
|
|
fullWidth
|
|
helperText="Must be a valid number"
|
|
value={secondaryCost}
|
|
error={isNaN(+secondaryCost) && secondaryCost !== ""}
|
|
InputProps={{
|
|
startAdornment: <InputAdornment position="start">$</InputAdornment>
|
|
}}
|
|
onChange={e => {
|
|
setSecondaryCost(e.target.value);
|
|
}}
|
|
/>
|
|
)}
|
|
{/* if the calendar was clicked gets the start date from that otherwise it will default to today */}
|
|
<TextField
|
|
style={{ width: "45%" }}
|
|
margin="normal"
|
|
type="date"
|
|
label="Start Date"
|
|
value={startDate}
|
|
onChange={e => setStartDate(e.target.value)}
|
|
/>
|
|
<TextField
|
|
style={{ width: "45%", marginLeft: "10%" }}
|
|
margin="normal"
|
|
type="time"
|
|
label="Start Time"
|
|
value={startTime}
|
|
onChange={e => setStartTime(e.target.value)}
|
|
/>
|
|
<TextField
|
|
style={{ width: "45%" }}
|
|
margin="normal"
|
|
type="date"
|
|
label="End Date"
|
|
value={endDate}
|
|
InputLabelProps={{ shrink: true }}
|
|
onChange={e => setEndDate(e.target.value)}
|
|
/>
|
|
<TextField
|
|
style={{ width: "45%", marginLeft: "10%" }}
|
|
margin="normal"
|
|
type="time"
|
|
label="End Time"
|
|
value={endTime}
|
|
onChange={e => setEndTime(e.target.value)}
|
|
/>
|
|
<Box marginTop={3}>
|
|
Colour
|
|
<ColourPicker onChange={color => setColour(color)} />
|
|
</Box>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Button onClick={closeDialog} variant="contained" style={{ margin: 5 }} color="primary">
|
|
Cancel
|
|
</Button>
|
|
{props.task ? (
|
|
<Button
|
|
onClick={updateTask}
|
|
variant="contained"
|
|
style={{ margin: 5 }}
|
|
color="primary"
|
|
disabled={!formComplete()}>
|
|
Update
|
|
</Button>
|
|
) : (
|
|
<Button
|
|
onClick={newTask}
|
|
variant="contained"
|
|
style={{ margin: 5 }}
|
|
color="primary"
|
|
disabled={!formComplete()}>
|
|
Create Task
|
|
</Button>
|
|
)}
|
|
</DialogActions>
|
|
</ResponsiveDialog>
|
|
);
|
|
}
|