feat: Update task status from 'Backlog' to 'To Do', adjust image source paths, and enhance task rendering in various components

This commit is contained in:
2024-11-06 17:32:12 +02:00
parent 55e81899ea
commit a06a190574
13 changed files with 120 additions and 46 deletions

View File

@@ -13,7 +13,7 @@ const ModalNewTask = ({ isOpen, onClose, id = null }: Props) => {
const [createTask, { isLoading }] = useCreateTaskMutation(); const [createTask, { isLoading }] = useCreateTaskMutation();
const [title, setTitle] = useState(""); const [title, setTitle] = useState("");
const [description, setDescription] = useState(""); const [description, setDescription] = useState("");
const [status, setStatus] = useState<Status>(Status.Backlog); const [status, setStatus] = useState<Status>(Status.ToDo);
const [priority, setPriority] = useState<Priority>(Priority.Backlog); const [priority, setPriority] = useState<Priority>(Priority.Backlog);
const [tags, setTags] = useState(""); const [tags, setTags] = useState("");
const [startDate, setStartDate] = useState(""); const [startDate, setStartDate] = useState("");
@@ -87,7 +87,7 @@ const ModalNewTask = ({ isOpen, onClose, id = null }: Props) => {
} }
> >
<option value="">Select Status</option> <option value="">Select Status</option>
<option value={Status.Backlog}>Backlog</option> <option value={Status.ToDo}>Backlog</option>
<option value={Status.InProgress}>In Progress</option> <option value={Status.InProgress}>In Progress</option>
<option value={Status.TestReview}>Test/Review</option> <option value={Status.TestReview}>Test/Review</option>
<option value={Status.Done}>Done</option> <option value={Status.Done}>Done</option>

View File

@@ -25,11 +25,13 @@ import { usePathname } from "next/navigation";
import { setIsSidebarCollapsed } from "@/state"; import { setIsSidebarCollapsed } from "@/state";
import { useAppDispatch, useAppSelector } from "@/app/redux"; import { useAppDispatch, useAppSelector } from "@/app/redux";
import Link from "next/link"; import Link from "next/link";
import { useGetProjectsQuery } from "@/state/api";
const Sidebar = () => { const Sidebar = () => {
const [showProjects, setShowProjects] = React.useState(true); const [showProjects, setShowProjects] = React.useState(true);
const [showPriority, setShowPriority] = React.useState(true); const [showPriority, setShowPriority] = React.useState(true);
const { data: projects } = useGetProjectsQuery();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const isSidebarCollapsed = useAppSelector( const isSidebarCollapsed = useAppSelector(
(state) => state.global.isSidebarCollapsed, (state) => state.global.isSidebarCollapsed,
@@ -77,7 +79,12 @@ const Sidebar = () => {
</nav> </nav>
<button <button
onClick={() => setShowProjects((prev) => !prev)} onClick={() =>
setShowProjects((prev) => {
console.log(prev);
return !prev;
})
}
className="flex w-full items-center justify-between px-8 py-3 text-gray-500" className="flex w-full items-center justify-between px-8 py-3 text-gray-500"
> >
<span className="">Projects</span> <span className="">Projects</span>
@@ -87,6 +94,15 @@ const Sidebar = () => {
<ChevronUpCircleIcon className="h-5 w-5" /> <ChevronUpCircleIcon className="h-5 w-5" />
)} )}
</button> </button>
{showProjects &&
projects?.map((project) => (
<SidebarLink
key={project.id}
icon={Briefcase}
label={project.name}
href={`/projects/${project.id}`}
/>
))}
<button <button
onClick={() => setShowPriority((prev) => !prev)} onClick={() => setShowPriority((prev) => !prev)}

View File

@@ -16,7 +16,7 @@ const TaskCard = ({ task }: Props) => {
<div className="flex flex-wrap"> <div className="flex flex-wrap">
{task.attachments && task.attachments.length > 0 && ( {task.attachments && task.attachments.length > 0 && (
<Image <Image
src={`${task.attachments[0].fileURL}`} src={`/${task.attachments[0].fileURL}`}
alt={task.attachments[0].fileName} alt={task.attachments[0].fileName}
width={400} width={400}
height={200} height={200}

View File

@@ -11,7 +11,7 @@ const UserCard = ({ user }: Props) => {
<div className="flex items-center rounded border p-4 shadow"> <div className="flex items-center rounded border p-4 shadow">
{user.profilePictureUrl && ( {user.profilePictureUrl && (
<Image <Image
src={`${user.profilePictureUrl}`} src={`/${user.profilePictureUrl}`}
alt="profile picture" alt="profile picture"
width={32} width={32}
height={32} height={32}

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
"use client"; "use client";
import { import {
@@ -5,7 +6,7 @@ import {
Project, Project,
Task, Task,
useGetProjectsQuery, useGetProjectsQuery,
useGetTasksQuery, useGetTasksByUserQuery,
} from "@/state/api"; } from "@/state/api";
import React from "react"; import React from "react";
import { useAppSelector } from "../redux"; import { useAppSelector } from "../redux";
@@ -28,19 +29,62 @@ import { dataGridSxStyles } from "@/lib/utils";
const taskColumns: GridColDef[] = [ const taskColumns: GridColDef[] = [
{ field: "title", headerName: "Title", width: 200 }, { field: "title", headerName: "Title", width: 200 },
{ field: "status", headerName: "Status", width: 150 }, {
{ field: "priority", headerName: "Priority", width: 150 }, 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 }, { field: "dueDate", headerName: "Due Date", width: 150 },
]; ];
const statusColors = ["#0088FE", "#00C49F", "#FFBB28", "#FF8042"]; const statusColors = ["#0088FE", "#00C49F", "#FFBB28", "#FF8042"];
const HomePage = () => { const HomePage = () => {
const userId = 1;
const { const {
data: tasks, data: tasks,
isLoading: tasksLoading, isLoading: tasksLoading,
isError: tasksError, isError: tasksError,
} = useGetTasksQuery({ projectId: parseInt("1") }); } = useGetTasksByUserQuery(userId || 0, {
skip: userId === null,
});
const { data: projects, isLoading: isProjectsLoading } = const { data: projects, isLoading: isProjectsLoading } =
useGetProjectsQuery(); useGetProjectsQuery();

View File

@@ -83,6 +83,8 @@ const ReusablePriorityPage = ({ priority }: Props) => {
skip: userId === null, skip: userId === null,
}); });
console.log(tasks);
const isDarkMode = useAppSelector((state) => state.global.isDarkMode); const isDarkMode = useAppSelector((state) => state.global.isDarkMode);
const filteredTasks = tasks?.filter( const filteredTasks = tasks?.filter(

View File

@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import React from "react";
import { useGetTasksQuery, useUpdateTaskStatusMutation } from "@/state/api"; import { useGetTasksQuery, useUpdateTaskStatusMutation } from "@/state/api";
import React from "react";
import { DndProvider, useDrag, useDrop } from "react-dnd"; import { DndProvider, useDrag, useDrop } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend"; import { HTML5Backend } from "react-dnd-html5-backend";
import { Task as TaskType } from "@/state/api"; import { Task as TaskType } from "@/state/api";
@@ -13,28 +13,27 @@ type BoardProps = {
setIsModalNewTaskOpen: (isOpen: boolean) => void; setIsModalNewTaskOpen: (isOpen: boolean) => void;
}; };
const taskStatuses = ["Backlog", "In Progress", "Test/Review", "Done"]; const taskStatus = ["To Do", "In Progress", "Test/Review", "Done"];
function BoardView({ id, setIsModalNewTaskOpen }: BoardProps) { const BoardView = ({ id, setIsModalNewTaskOpen }: BoardProps) => {
const { const {
data: tasks, data: tasks,
isLoading, isLoading,
error, error,
} = useGetTasksQuery({ projectId: Number(id) }); } = useGetTasksQuery({ projectId: Number(id) });
const [updateTaskStatus] = useUpdateTaskStatusMutation(); const [updateTaskStatus] = useUpdateTaskStatusMutation();
const moveTask = (taskId: number, status: string) => { const moveTask = (taskId: number, toStatus: string) => {
updateTaskStatus({ taskId, status }); updateTaskStatus({ taskId, status: toStatus });
}; };
if (isLoading) return <div>Loading...</div>; if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error fetching tasks</div>; if (error) return <div>An error occurred while fetching tasks</div>;
return ( return (
<DndProvider backend={HTML5Backend}> <DndProvider backend={HTML5Backend}>
<div className="grid grid-cols-1 gap-4 p-4 md:grid-cols-2 xl:grid-cols-4"> <div className="grid grid-cols-1 gap-4 p-4 md:grid-cols-2 xl:grid-cols-4">
{taskStatuses.map((status) => ( {taskStatus.map((status) => (
<TaskColumn <TaskColumn
key={status} key={status}
status={status} status={status}
@@ -46,7 +45,7 @@ function BoardView({ id, setIsModalNewTaskOpen }: BoardProps) {
</div> </div>
</DndProvider> </DndProvider>
); );
} };
type TaskColumnProps = { type TaskColumnProps = {
status: string; status: string;
@@ -63,10 +62,8 @@ const TaskColumn = ({
}: TaskColumnProps) => { }: TaskColumnProps) => {
const [{ isOver }, drop] = useDrop(() => ({ const [{ isOver }, drop] = useDrop(() => ({
accept: "task", accept: "task",
drop: (item: { id: number }) => { drop: (item: { id: number }) => moveTask(item.id, status),
moveTask(item.id, status); collect: (monitor: any) => ({
},
collect: (monitor) => ({
isOver: !!monitor.isOver(), isOver: !!monitor.isOver(),
}), }),
})); }));
@@ -74,7 +71,7 @@ const TaskColumn = ({
const tasksCount = tasks.filter((task) => task.status === status).length; const tasksCount = tasks.filter((task) => task.status === status).length;
const statusColors: any = { const statusColors: any = {
Backlog: "#800000", "To Do": "#800000",
"In Progress": "#efcc00", "In Progress": "#efcc00",
"Test/Review": "#00008b", "Test/Review": "#00008b",
Done: "#006400", Done: "#006400",
@@ -178,7 +175,7 @@ const Task = ({ task }: TaskProps) => {
> >
{task.attachments && task.attachments.length > 0 && ( {task.attachments && task.attachments.length > 0 && (
<Image <Image
src={`${task.attachments[0].fileURL}`} src={`/${task.attachments[0].fileURL}`}
alt={task.attachments[0].fileName} alt={task.attachments[0].fileName}
width={400} width={400}
height={200} height={200}
@@ -230,7 +227,7 @@ const Task = ({ task }: TaskProps) => {
{task.assignee && ( {task.assignee && (
<Image <Image
key={task.assignee.userId} key={task.assignee.userId}
src={`${task.assignee.profilePictureUrl!}`} src={`/${task.assignee.profilePictureUrl!}`}
alt={task.assignee.username} alt={task.assignee.username}
width={30} width={30}
height={30} height={30}
@@ -240,7 +237,7 @@ const Task = ({ task }: TaskProps) => {
{task.author && ( {task.author && (
<Image <Image
key={task.author.userId} key={task.author.userId}
src={`${task.author.profilePictureUrl!}`} src={`/${task.author.profilePictureUrl!}`}
alt={task.author.username} alt={task.author.username}
width={30} width={30}
height={30} height={30}

View File

@@ -11,13 +11,6 @@ type Props = {
setIsModalNewTaskOpen: (isOpen: boolean) => void; setIsModalNewTaskOpen: (isOpen: boolean) => void;
}; };
const statusClasses: any = {
Backlog: "bg-red-400 text-red-800",
"In Progress": "bg-yellow-400 text-yellow-800",
"Test/Review": "bg-blue-400 text-blue-800",
Done: "bg-green-400 text-green-800",
};
const columns: GridColDef[] = [ const columns: GridColDef[] = [
{ {
field: "title", field: "title",
@@ -33,10 +26,17 @@ const columns: GridColDef[] = [
field: "status", field: "status",
headerName: "Status", headerName: "Status",
width: 130, width: 130,
// Render a colored badge in className based on the status
renderCell: (params) => ( renderCell: (params) => (
<span <span
className={`inline-flex rounded-full px-2 text-xs font-semibold leading-5 ${statusClasses[params.value] || "bg-gray-400 text-gray-800"}`} 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} {params.value}
</span> </span>
@@ -46,6 +46,23 @@ const columns: GridColDef[] = [
field: "priority", field: "priority",
headerName: "Priority", headerName: "Priority",
width: 75, width: 75,
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: "tags", field: "tags",

View File

@@ -1,19 +1,19 @@
"use client"; "use client";
import React, { useState } from "react"; import React, { use, useState } from "react";
import ProjectHeader from "@/app/projects/ProjectHeader"; import ProjectHeader from "@/app/projects/ProjectHeader";
import Board from "@/app/projects/BoardView"; import Board from "../BoardView";
import List from "@/app/projects/ListView"; import List from "../ListView";
import Timeline from "@/app/projects/TimelineView"; import Timeline from "../TimelineView";
import Table from "@/app/projects/TableView"; import Table from "../TableView";
import ModalNewTask from "@/app/components/ModalNewTask"; import ModalNewTask from "@/app/components/ModalNewTask";
type Props = { type Props = {
params: { id: string }; params: Promise<{ id: string }>;
}; };
const Project = ({ params }: Props) => { const Project = ({ params }: Props) => {
const { id } = params; const { id } = use(params);
const [activeTab, setActiveTab] = useState("Board"); const [activeTab, setActiveTab] = useState("Board");
const [isModalNewTaskOpen, setIsModalNewTaskOpen] = useState(false); const [isModalNewTaskOpen, setIsModalNewTaskOpen] = useState(false);
@@ -25,7 +25,6 @@ const Project = ({ params }: Props) => {
id={id} id={id}
/> />
<ProjectHeader activeTab={activeTab} setActiveTab={setActiveTab} /> <ProjectHeader activeTab={activeTab} setActiveTab={setActiveTab} />
{activeTab === "Board" && ( {activeTab === "Board" && (
<Board id={id} setIsModalNewTaskOpen={setIsModalNewTaskOpen} /> <Board id={id} setIsModalNewTaskOpen={setIsModalNewTaskOpen} />
)} )}

View File

@@ -8,7 +8,6 @@ const Settings = () => {
teamName: "mockteam", teamName: "mockteam",
roleName: "mockrole", roleName: "mockrole",
}; };
const labelStyles = "block text-sm font-medium dark:text-white"; const labelStyles = "block text-sm font-medium dark:text-white";
const textStyles = const textStyles =
"mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2 dark:text-white"; "mt-1 block w-full border border-gray-300 rounded-md shadow-sm p-2 dark:text-white";

View File

@@ -31,7 +31,7 @@ const columns: GridColDef[] = [
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<div className="h-9 w-9"> <div className="h-9 w-9">
<Image <Image
src={`${params.value}`} src={`/${params.value}`}
alt={params.row.username} alt={params.row.username}
width={100} width={100}
height={50} height={50}

View File

@@ -17,7 +17,7 @@ export enum Priority {
} }
export enum Status { export enum Status {
Backlog = "Backlog", ToDo = "To Do",
InProgress = "In Progress", InProgress = "In Progress",
TestReview = "Test/Review", TestReview = "Test/Review",
Done = "Done", Done = "Done",