Task detail page finalized and added user loading skeleton

This commit is contained in:
Thastertyn committed 2025-06-23 00:09:21 +02:00
1 parent 2204ffeece
commit e5e565430c
7 files changed
+126 -23

No files matched your search

+2 -5
View File
@@ -24,7 +24,7 @@ const TaskComponent: React.FC<TaskComponentProps> = ({ task }) => {
return (
<ListItem
className="task-list-item"
className={`task-list-item ${task.finished && "finished"}`}
onClick={() => navigate(`/task/${task.id}`)}
>
<Grid container spacing={2} alignItems="center" width={"100%"}>
@@ -38,14 +38,11 @@ const TaskComponent: React.FC<TaskComponentProps> = ({ task }) => {
Assigned to: {assignedToUser}
</Typography>
</Grid>
<Grid size={3}>
<Grid size={4}>
<Typography variant="body1" color="text.secondary">
Due: {task.due}
</Typography>
</Grid>
<Grid size={1}>
<input type="checkbox" checked={task.finished} disabled={true} />
</Grid>
</Grid>
</ListItem>
);
+95 -1
View File
@@ -1,7 +1,101 @@
import React from "react";
import { useNavigate, useParams } from "react-router-dom";
import { TaskContext } from "../contexts/taskContext";
import { useContext } from "react";
import {
Button,
Card,
CardContent,
CardHeader,
Divider,
Stack,
Typography,
} from "@mui/material";
import { UserContext } from "../contexts/userContext";
import type { User } from "../utils/types";
const TaskDetail: React.FC = () => {
return <div></div>;
const navigate = useNavigate();
const { taskId } = useParams();
const { tasks, setTasks } = useContext(TaskContext);
const { users, loading } = useContext(UserContext);
const numerizedTaskId = Number(taskId);
const taskInQuestion = tasks.find((task) => task.id === numerizedTaskId);
if (!taskInQuestion) return <div>Task not found</div>;
let userInQuestion: User | undefined;
if (users && !loading) {
userInQuestion = users.find(
(user) => user.id === taskInQuestion?.assignedTo,
);
}
function markFinished() {
setTasks((prevTasks) =>
prevTasks.map((task) =>
// @ts-expect-error The function is called after the check. It's safe to assume taskInQuestion is not undefined
task.id === taskInQuestion.id
? { ...task, finished: !task.finished }
: task,
),
);
navigate(-1);
}
return (
<Card>
<CardHeader title={`Task #${taskInQuestion.id}`} />
<CardContent>
<Stack spacing={2}>
<Typography variant="subtitle1" color="text.primary">
{taskInQuestion.text}
</Typography>
<Divider />
<Typography variant="body2" color="text.secondary" align="left">
<b>Assigned to:</b>{" "}
{userInQuestion
? `${userInQuestion.name} <${userInQuestion.email}>`
: "Unknown user"}
</Typography>
<Typography variant="body2" color="text.secondary" align="left">
<b>Due date:</b> {taskInQuestion.due}
</Typography>
<Typography variant="body2" color="text.secondary" align="left">
<b>Created at:</b>{" "}
{taskInQuestion.createdAt.current.toLocaleString()}
</Typography>
<Divider />
<Stack
direction="row"
spacing={2}
justifyContent="space-between"
>
<Button variant="outlined" onClick={() => navigate(-1)}>
Go back
</Button>
<Button
variant="contained"
color="primary"
onClick={markFinished}
>
{!taskInQuestion.finished ? "Mark finished" : "Undo"}
</Button>
</Stack>
</Stack>
</CardContent>
</Card>
);
};
export default TaskDetail;
+3 -2
View File
@@ -10,6 +10,7 @@ import {
Button,
Card,
CardHeader,
Skeleton,
TextField,
} from "@mui/material";
import { DatePicker } from "@mui/x-date-pickers/DatePicker";
@@ -37,6 +38,7 @@ const TaskForm: React.FC = () => {
const creationDate = useRef<Date>(new Date());
function addTask(data: FormValues) {
creationDate.current = new Date();
const currentIdMaxId = Math.max(...tasks.map((task) => task.id)) + 1;
const newId = Math.max(currentIdMaxId, 1);
@@ -53,8 +55,7 @@ const TaskForm: React.FC = () => {
reset();
}
// TODO make a skeleton
if (loading) return <div>Loading...</div>;
if (loading) return <Skeleton className="task-form-skeleton" />;
// TODO Better error display
if (users == null) return <div>{error}</div>;
+10 -1
View File
@@ -6,6 +6,15 @@ import { Card, List } from "@mui/material";
const TaskList: React.FC = () => {
const { tasks } = useContext(TaskContext);
// show unfinished tasks later and those with closer due date higher
const sortedTasks = tasks.sort((a, b) => {
if (a.finished == b.finished) {
if (a.due === b.due) return 0;
return a.due < b.due ? -1 : 1;
}
return a.finished ? 1 : -1;
});
return (
<div className="task-list">
<Card>
@@ -13,7 +22,7 @@ const TaskList: React.FC = () => {
<p>No tasks yet...</p>
) : (
<List>
{tasks.map((task, index) => (
{sortedTasks.map((task, index) => (
<TaskComponent key={index} task={task} />
))}
</List>
+11
View File
@@ -23,3 +23,14 @@
.task-list-item:hover {
background-color: #f0f0f0;
}
.task-list-item.finished {
text-decoration: line-through;
color: #888;
}
.task-form-skeleton {
width: 50vw;
max-width: 1000px;
height: 100px;
}
+3 -1
View File
@@ -1,7 +1,9 @@
import "@/css/MainPage.css";
import React from "react";
import TaskForm from "../components/TaskForm";
import TaskList from "../components/TaskList";
import "@/css/MainPage.css";
const MainPage: React.FC = () => {
return (
+2 -13
View File
@@ -1,19 +1,8 @@
import React from "react";
import { useParams } from "react-router-dom";
import { TaskContext } from "../contexts/taskContext";
import { useContext } from "react";
import TaskDetail from "../components/TaskDetail";
const TaskPage: React.FC = () => {
const { taskId } = useParams();
const numerizedTaskId = Number(taskId);
const { tasks } = useContext(TaskContext);
const taskInQuestion = tasks.find((task) => task.id === numerizedTaskId);
if (!taskInQuestion) return <div>Task not found</div>;
return <div>Task {taskId}</div>;
return <TaskDetail />;
};
export default TaskPage;