This repository has been archived on 2025-12-11. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
tasker/tasker-client/src/app/home/page.tsx
Andrew Trieu 11e61829f1 Wip backend (#4)
* feat: Add new API handlers for user, project, and task management; update package dependencies

* feat: Update .gitignore, add Lambda layer configuration, and refactor DynamoDB handlers to use AWS SDK v3

* feat: Update serverless configuration and refactor API handlers to improve error handling and response structure

* feat: Add Cognito user pool name parameter and update API handlers to include CORS headers

* feat: Update task and project ID formats, add populateSeedData function, and enhance user ID handling

* feat: Update image source paths to use S3 public URL for profile and task attachments
2024-11-23 18:17:00 +02:00

210 lines
6.2 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-explicit-any */
"use client";
import {
Priority,
Project,
Task,
useGetAuthUserQuery,
useGetProjectsQuery,
useGetTasksByUserQuery,
} from "@/state/api";
import React from "react";
import { useAppSelector } from "../redux";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
import Header from "@/app/components/Header";
import {
Bar,
BarChart,
CartesianGrid,
Cell,
Legend,
Pie,
PieChart,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts";
import { dataGridSxStyles } from "@/lib/utils";
const taskColumns: GridColDef[] = [
{ field: "title", headerName: "Title", width: 200 },
{
field: "status",
headerName: "Status",
width: 150,
renderCell: (params) => (
<span
className={`inline-flex rounded-full px-2 text-xs font-semibold leading-5 ${
params.value === "In Progress"
? "bg-green-200 text-green-600"
: params.value === "Test/Review"
? "bg-green-200 text-green-600"
: params.value === "Done"
? "bg-green-400 text-green-800"
: "bg-gray-400 text-gray-800"
}`}
>
{params.value}
</span>
),
},
{
field: "priority",
headerName: "Priority",
width: 150,
renderCell: (params) => (
<span
className={`inline-flex rounded-full px-2 text-xs font-semibold leading-5 ${
params.value === "Urgent"
? "bg-red-200 text-red-700"
: params.value === "High"
? "bg-yellow-200 text-yellow-700"
: params.value === "Medium"
? "bg-green-200 text-green-700"
: params.value === "Low"
? "bg-blue-200 text-blue-700"
: "bg-gray-200 text-gray-700"
}`}
>
{params.value}
</span>
),
},
{ field: "dueDate", headerName: "Due Date", width: 150 },
];
const statusColors = ["#0088FE", "#00C49F", "#FFBB28", "#FF8042"];
const HomePage = () => {
const { data: currentUser } = useGetAuthUserQuery({});
const userId = currentUser?.userDetails?.userId ?? null;
const {
data: tasks,
isLoading: tasksLoading,
isError: tasksError,
} = useGetTasksByUserQuery(userId || "", {
skip: userId === null,
});
const { data: projects, isLoading: isProjectsLoading } =
useGetProjectsQuery();
const isDarkMode = useAppSelector((state) => state.global.isDarkMode);
if (tasksLoading || isProjectsLoading) return <div>Loading..</div>;
if (tasksError || !tasks || !projects) return <div>Error fetching data</div>;
const priorityCount = tasks.reduce(
(acc: Record<string, number>, task: Task) => {
const { priority } = task;
acc[priority as Priority] = (acc[priority as Priority] || 0) + 1;
return acc;
},
{},
);
const taskDistribution = Object.keys(priorityCount).map((key) => ({
name: key,
count: priorityCount[key],
}));
const statusCount = projects.reduce(
(acc: Record<string, number>, project: Project) => {
const status = project.endDate ? "Completed" : "Active";
acc[status] = (acc[status] || 0) + 1;
return acc;
},
{},
);
const projectStatus = Object.keys(statusCount).map((key) => ({
name: key,
count: statusCount[key],
}));
const chartColors = isDarkMode
? {
bar: "#8884d8",
barGrid: "#303030",
pieFill: "#4A90E2",
text: "#FFFFFF",
}
: {
bar: "#8884d8",
barGrid: "#E0E0E0",
pieFill: "#82ca9d",
text: "#000000",
};
return (
<div className="container h-full w-[100%] bg-gray-100 bg-transparent p-8">
<Header name="Project Management Dashboard" />
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div className="rounded-lg bg-white p-4 shadow dark:bg-dark-secondary">
<h3 className="mb-4 text-lg font-semibold dark:text-white">
Task Priority Distribution
</h3>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={taskDistribution}>
<CartesianGrid
strokeDasharray="3 3"
stroke={chartColors.barGrid}
/>
<XAxis dataKey="name" stroke={chartColors.text} />
<YAxis stroke={chartColors.text} />
<Tooltip
contentStyle={{
width: "min-content",
height: "min-content",
}}
/>
<Legend />
<Bar dataKey="count" fill={chartColors.bar} />
</BarChart>
</ResponsiveContainer>
</div>
<div className="rounded-lg bg-white p-4 shadow dark:bg-dark-secondary">
<h3 className="mb-4 text-lg font-semibold dark:text-white">
Project Status
</h3>
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie dataKey="count" data={projectStatus} fill="#82ca9d" label>
{projectStatus.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={statusColors[index % statusColors.length]}
/>
))}
</Pie>
<Tooltip />
<Legend />
</PieChart>
</ResponsiveContainer>
</div>
<div className="rounded-lg bg-white p-4 shadow dark:bg-dark-secondary md:col-span-2">
<h3 className="mb-4 text-lg font-semibold dark:text-white">
Your Tasks
</h3>
<div style={{ height: 400, width: "100%" }}>
<DataGrid
rows={tasks}
columns={taskColumns}
checkboxSelection
loading={tasksLoading}
getRowId={(row) => row.taskId}
getRowClassName={() => "data-grid-row"}
getCellClassName={() => "data-grid-cell"}
className="border border-gray-200 bg-white shadow dark:border-stroke-dark dark:bg-dark-secondary dark:text-gray-200"
sx={dataGridSxStyles(isDarkMode)}
/>
</div>
</div>
</div>
</div>
);
};
export default HomePage;