added tasks page and functionality

This commit is contained in:
csawatzky 2025-04-07 15:46:59 -06:00
parent b573e10707
commit 2ef22a8bc2
19 changed files with 1992 additions and 15 deletions

323
src/tasks/TaskDrawer.tsx Normal file
View file

@ -0,0 +1,323 @@
import {
Avatar,
Box,
Card,
Drawer,
Grid2 as Grid,
IconButton,
ListItemIcon,
ListItemText,
Menu,
MenuItem,
Slider,
Theme,
Tooltip,
Typography
} from "@mui/material";
import { Done, Edit, MoreVert } from "@mui/icons-material";
import DisplayDrawer from "common/DisplayDrawer";
import { Task } from "models";
import { useEffect, useState } from "react";
import NotesIcon from "@mui/icons-material/Notes";
import DeleteIcon from "@mui/icons-material/Delete";
import Chat from "chat/Chat";
import { pond } from "protobuf-ts/pond";
import { useMobile, useUserAPI } from "hooks";
import { getThemeType } from "theme";
import { makeStyles } from "@mui/styles";
interface Props {
task: Task;
open: boolean;
closeCallback: () => void;
editTask: (task: Task) => void;
deleteTask: (task: Task) => void;
completeTask: (task: Task) => void;
}
// interface TabPanelProps {
// children?: React.ReactNode;
// index: any;
// value: any;
// }
const useStyles = makeStyles((theme: Theme) => ({
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
},
sliderRoot: {},
sliderThumb: {
height: 15,
width: 15,
marginTop: 0,
marginLeft: 0,
backgroundColor: "yellow"
},
sliderTrack: {
height: 3,
backgroundColor: "white"
},
sliderRail: {
height: 3,
backgroundColor: "white"
},
sliderValLabel: {
left: -20,
top: 40,
background: "transparent",
"& *": {
color: "#fff"
}
},
sliderMark: {
visibility: "hidden"
},
sliderMarked: {
marginTop: 25,
marginBottom: 0
},
sliderMarkLabel: {
top: -25,
left: -10
}
})
);
export default function TaskDrawer(props: Props) {
const monthList = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"June",
"July",
"Aug",
"Sept",
"Oct",
"Nov",
"Dec"
];
const { task, open, closeCallback, completeTask, deleteTask, editTask } = props;
const [month, setMonth] = useState(0);
const [day, setDay] = useState(0);
const [menuAnchorEl, setMenuAnchorEl] = useState<Element | null>(null);
const [openNote, setOpenNote] = useState(false);
const isMobile = useMobile();
const classes = useStyles();
const userAPI = useUserAPI();
const [worker, setWorker] = useState<pond.UserProfile>();
useEffect(() => {
if (task.start()) {
let date = new Date(task.start());
setMonth(date.getUTCMonth());
setDay(date.getUTCDate());
}
userAPI.getProfile(task.worker()).then(resp => {
setWorker(resp);
});
}, [task, userAPI]);
const taskActions = () => {
return (
<Menu
id="viewMenu"
anchorEl={menuAnchorEl ? menuAnchorEl : null}
open={menuAnchorEl !== null}
onClose={() => setMenuAnchorEl(null)}
disableAutoFocusItem>
<MenuItem
onClick={() => {
editTask(props.task);
setMenuAnchorEl(null);
}}>
<ListItemIcon>
<Edit />
</ListItemIcon>
<ListItemText primary="Edit" />
</MenuItem>
<MenuItem
onClick={() => {
deleteTask(props.task);
setMenuAnchorEl(null);
closeCallback();
}}>
<ListItemIcon>
<DeleteIcon style={{ color: "red" }} />
</ListItemIcon>
<ListItemText primary="Delete" />
</MenuItem>
</Menu>
);
};
const bodyButtons = () => {
return (
<Grid container direction="row" alignItems="center" justifyContent="space-between">
<Grid>
<Tooltip title="Task Notes">
<IconButton className={classes.avatar} onClick={() => setOpenNote(true)}>
<NotesIcon />
</IconButton>
</Tooltip>
<IconButton style={{ visibility: "hidden" }}>3</IconButton> {/** go to bin/field */}
</Grid>
<Grid>
<Tooltip title="Mark Complete">
<IconButton className={classes.avatar} onClick={() => completeTask(task)}>
<Done style={{ color: task.complete() ? "green" : "white" }} />
</IconButton>
</Tooltip>
<Tooltip title="More">
<IconButton
className={classes.avatar}
onClick={event => setMenuAnchorEl(event.currentTarget)}>
<MoreVert />
</IconButton>
</Tooltip>
</Grid>
</Grid>
);
};
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_TASK} objectKey={task.key} />
</Box>
</Drawer>
);
};
const taskCard = () => {
return (
<Card style={{ height: "35%", paddingTop: 10 }}>
<Grid container direction="row" alignItems="center">
<Grid size={2}>
<Box
style={{
border: "1px solid white",
width: "50px",
height: "50px",
borderRadius: 5,
margin: "auto",
verticalAlign: "middle",
lineHeight: "50px",
textAlign: "center"
}}>
<Typography>{monthList[month]}</Typography>
<Typography style={{ fontWeight: 750 }}>{day}</Typography>
</Box>
</Grid>
<Grid size={10}>
<Typography style={{ fontWeight: 700, fontSize: 30 }}>{task.title()}</Typography>
</Grid>
</Grid>
<Box padding={3}>{task.description()}</Box>
</Card>
);
};
const taskTime = () => {
let start = task
? new Date(task.start() + "T" + task.startTime()).valueOf()
: new Date().valueOf();
let end = task ? new Date(task.end() + "T" + task.endTime()).valueOf() : new Date().valueOf();
return (
<Box style={{ height: "30%" }}>
<Grid container direction="row" alignItems="center" style={{ height: "100%" }}>
<Grid size={3}>
<Box style={{ textAlign: "center" }}>
<Typography>{task.start()}</Typography>
<Typography>{task.startTime()}</Typography>
</Box>
</Grid>
<Grid size={6}>
<Slider
classes={{
root: classes.sliderRoot,
rail: classes.sliderRail,
track: classes.sliderTrack,
thumb: classes.sliderThumb,
valueLabel: classes.sliderValLabel,
marked: classes.sliderMarked,
mark: classes.sliderMark,
markLabel: classes.sliderMarkLabel
}}
min={start}
max={end}
value={new Date().valueOf()} />
</Grid>
<Grid size={3}>
<Box style={{ textAlign: "center" }}>
<Typography>{task.end()}</Typography>
<Typography>{task.endTime()}</Typography>
</Box>
</Grid>
</Grid>
</Box>
);
};
const assignees = () => {
return (
<Card style={{ height: "35%" }}>
<Box padding={2}>
<Typography style={{ fontWeight: 700, fontSize: 30 }}>Assigned To:</Typography>
{/* TODO: change this to get the user and display the user name and avatar */}
{worker && (
<Grid container direction="row" alignItems="center">
<Grid>
<Avatar
alt={worker.name}
src={worker.avatar && worker.avatar !== "" ? worker.avatar : undefined}
/>
</Grid>
<Grid>
<Box marginLeft={2}>{worker.name}</Box>
</Grid>
</Grid>
)}
</Box>
</Card>
);
};
const drawerBody = () => {
return (
<Box padding={2}>
{bodyButtons()}
<Box marginTop={3} style={{ height: "65vh" }}>
{taskCard()}
{taskTime()}
{assignees()}
</Box>
{taskActions()}
{noteDrawer()}
</Box>
);
};
return (
<DisplayDrawer
width={500}
title={task.title()}
displayNext={() => {}}
displayPrev={() => {}}
drawerBody={drawerBody()}
onClose={closeCallback}
open={open}
/>
);
}