diff --git a/app/(app)/dashboard/KanbanCard.tsx b/app/(app)/dashboard/KanbanCard.tsx index de35e56..ff32225 100644 --- a/app/(app)/dashboard/KanbanCard.tsx +++ b/app/(app)/dashboard/KanbanCard.tsx @@ -1,62 +1,117 @@ /** * @file dashboard/KanbanCard.tsx - * @description Client component rendering a simplified kanban task card displaying title, priority, description, and metadata. + * @description Client component rendering an individual task card within a kanban column, featuring priority configuration, due dates, overdue highlights, and user avatars. */ "use client"; - +import { AlertCircle, Crown, CalendarDays } from "lucide-react"; import { KanbanCardProps } from "@/types/tasks"; /** - * Renders a task card component with a basic layout for title, priority, description, due date, and creator info. + * Renders a task card component displaying its title, priority badge, description, + * deadline with hover time details, and creator/assignee avatars. * * @param {KanbanCardProps} props - The component props containing the task object. * @returns {JSX.Element} The rendered kanban card component. */ export default function KanbanCard({ task }: KanbanCardProps) { - const assignees = task.assignees || []; + const isOverdue = + task.dueDate && + new Date(task.dueDate) < new Date() && + task.status !== "done"; + + const filteredAssignees = (task.assignees || []).filter( + (a) => a !== task.creator, + ); return ( -
- {/* Title & Priority */} +
+ {/* --- Card Header (Title & Priority) --- */}
- {task.title} + {/* Title */} +

+ {task.title} +

+ + {/* Priority Badge */} {task.priority && ( - {task.priority} + + {task.priority.charAt(0).toUpperCase() + task.priority.slice(1)} + )}
- {/* Description */} - {task.description && ( -

{task.description}

- )} + {/* Card Description */} +

+ {task.description} +

- {/* Footer / Meta & People */} -
-
- {task.dueDate && ( - {new Date(task.dueDate).toLocaleDateString()} - )} -
+ {/* --- Card Footer (Date, Mobile Action Menu, Avatars) --- */} +
+ {/* Left Side: Date Badge */} + {task.dueDate && ( +
+ {isOverdue ? : } + + {new Date(task.dueDate).toLocaleDateString("de-DE", { + day: "2-digit", + month: "short", + })} + -
- {task.creator && ( - - {task.creator.substring(0, 2).toUpperCase()} + {/* Time displayed when hovering over the badge */} + + + {new Date(task.dueDate).toLocaleTimeString("de-DE", { + hour: "2-digit", + minute: "2-digit", + })} + +
+ )} + + {/* Right Side: Avatars & Mobile Switcher */} +
+ {/* Avatars */} + {(task.creator || filteredAssignees.length > 0) && ( +
+ {filteredAssignees.map((assignee, index) => ( +
+ {assignee.substring(0, 2).toUpperCase()} +
+ ))} + {task.creator && ( +
+ {task.creator.substring(0, 2).toUpperCase()} + + + +
+ )} +
)} - {assignees.map((assignee, index) => ( - - {assignee.substring(0, 2).toUpperCase()} - - ))}
diff --git a/app/(app)/dashboard/KanbanColumn.tsx b/app/(app)/dashboard/KanbanColumn.tsx index eccdeb2..7a6bbc1 100644 --- a/app/(app)/dashboard/KanbanColumn.tsx +++ b/app/(app)/dashboard/KanbanColumn.tsx @@ -1,6 +1,6 @@ /** * @file dashboard/KanbanColumn.tsx - * @description Client component rendering a single column in the kanban board, containing a status header, count, task list, and fallback empty states. + * @description Client component rendering an individual kanban column container with its header, task count, action button, and list of task cards. */ "use client"; @@ -10,39 +10,49 @@ import KanbanCard from "./KanbanCard"; import { KanbanColumnProps } from "@/types/tasks"; /** - * Renders a kanban column with an indicator color, title, task count, quick-add trigger, - * and a list of rendered task cards or an empty placeholder. + * Renders a kanban column containing a header with category indicator and counter, + * an add button, and a sorted list of associated task cards or an empty placeholder. * - * @param {KanbanColumnProps} props - The component props defining column metadata and task lists. + * @param {KanbanColumnProps} props - The component props including column details, task list, and styling options. * @returns {JSX.Element} The rendered kanban column component. */ export default function KanbanColumn(props: KanbanColumnProps) { + const indicatorColor = props.color ?? "bg-primary"; + return ( -
- {/* Header */} -
-
+
+ {/* Column Header */} +
+
-

{props.title}

- {props.count} +

+ {props.title} +

+ + {props.count} +
-
- {/* Task List */} -
+ {/* Card List */} + +
{props.tasks.length === 0 ? ( -
- No tasks +
+ No tasks
) : ( props.tasks.map((task) => ( -
- +
+
)) )} diff --git a/types/tasks.ts b/types/tasks.ts index 2bcb239..ffbe38b 100644 --- a/types/tasks.ts +++ b/types/tasks.ts @@ -3,13 +3,18 @@ * @description Type definitions, interfaces, and UI configuration mappings for task management and kanban views. */ -import { taskStatusEnum, type Task as DbTask } from "@/db/schema"; +import { + taskPriorityEnum, + taskStatusEnum, + type Task as DbTask, +} from "@/db/schema"; // ========================================== // Types // ========================================== export type TaskStatus = (typeof taskStatusEnum.enumValues)[number]; +export type TaskPriority = (typeof taskPriorityEnum.enumValues)[number]; // ========================================== // Interfaces @@ -21,6 +26,15 @@ export interface Task extends Omit { creator?: string; } +export interface RouteContext { + params: Promise<{ id: string }>; +} + +export interface TaskPriorityConfig { + label: string; + className: string; +} + export interface KanbanColumnConfig { id: TaskStatus; title: string; @@ -41,6 +55,21 @@ export interface KanbanCardProps { // UI Configurations // ========================================== +export const PRIORITY_CONFIG = { + high: { + label: "High", + className: "bg-rose-500/10 text-rose-500 border-rose-500/20", + }, + medium: { + label: "Medium", + className: "bg-amber-500/10 text-amber-500 border-amber-500/20", + }, + low: { + label: "Low", + className: "bg-zinc-500/10 text-zinc-400 border-zinc-500/20", + }, +} as const satisfies Record; + export const KANBAN_COLUMNS = [ { id: "todo", title: "To-do", color: "bg-zinc-400" }, { id: "in_progress", title: "In Progress", color: "bg-indigo-500" },