"use client"; import { useDroppable, useDraggable } from "@dnd-kit/core"; import { format, parseISO, formatDistanceToNow } from "date-fns"; import { cn } from "@/lib/utils"; import { CalendarDays, Clock, GripVertical, Layers, ChevronDown, } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { ScrollArea } from "@/components/ui/scroll-area"; import { TaskStatus, TaskType } from "@prisma/client"; import { ScheduleTask, ActiveDragData, } from "@/app/(dashboard)/schedule/SchedulePageClient"; import { TASK_STATUS_CONFIG, TASK_TYPE_LABELS } from "@/components/tasks/TaskCard"; const PRIORITY_DOT: Record = { LOW: "bg-zinc-500", NORMAL: "bg-blue-500", HIGH: "bg-amber-500", URGENT: "bg-red-500", }; function toDate(val: string | null | undefined): Date | null { if (!val) return null; try { return parseISO(val); } catch { return new Date(val); } } function BacklogItem({ task, canEdit, }: { task: ScheduleTask; canEdit: boolean; }) { const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({ id: task.id, disabled: !canEdit, data: { type: "backlog", taskId: task.id, estimatedHours: task.estimatedHours, } as ActiveDragData, }); const cfg = TASK_STATUS_CONFIG[task.status]; const StatusIcon = cfg.icon; const contextCode = task.shot?.shotCode ?? task.asset?.assetCode; const dueDate = toDate(task.dueDate); const isOverdue = dueDate && dueDate < new Date() && task.status !== "DONE"; const style = transform ? { transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, zIndex: 50, } : undefined; return (
{/* Grip */} {canEdit && ( )} {/* Priority dot */}
{/* Content */}
{contextCode && ( {contextCode} )} {task.title}
{TASK_TYPE_LABELS[task.type as TaskType]} ยท {task.project.code} {task.estimatedHours && ( {task.estimatedHours}h )}
{cfg.label} {dueDate && ( {formatDistanceToNow(dueDate, { addSuffix: true })} )}
); } interface BacklogPanelProps { tasks: ScheduleTask[]; canEdit: boolean; } export function BacklogPanel({ tasks, canEdit }: BacklogPanelProps) { const { setNodeRef, isOver } = useDroppable({ id: "backlog-drop-zone", }); return (
{/* Header */}
Backlog {tasks.length}
{canEdit && ( Drag onto timeline )}
{/* Drop zone + list */}
{tasks.length === 0 ? (

All tasks scheduled

{canEdit && (

Drop here to unschedule

)}
) : (
{canEdit && isOver && (
Drop to unschedule
)} {tasks.map((task) => ( ))}
)}
); }