{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"list-04","type":"registry:component","title":"Task Management List","description":"Comprehensive task management list with checkboxes, priority indicators, due date tracking, subtask progress, assignee information, and dropdown actions. Features overdue detection, priority-based styling, and comprehensive task management functionality.","dependencies":["lucide-react"],"registryDependencies":["avatar","badge","button","card","checkbox","dropdown-menu"],"files":[{"path":"src/registry/blocks/application/data-display/lists/list-04.tsx","content":"\"use client\";\n\nimport {\n  AlertCircle,\n  ArrowDown,\n  ArrowUp,\n  Calendar,\n  CheckCircle2,\n  type LucideIcon,\n  Minus,\n  MoreHorizontal,\n} from \"lucide-react\";\nimport { useState } from \"react\";\nimport { cn } from \"@/registry/lib/utils\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/registry/ui/avatar\";\nimport { Badge } from \"@/registry/ui/badge\";\nimport { Button } from \"@/registry/ui/button\";\nimport { Card, CardContent } from \"@/registry/ui/card\";\nimport { Checkbox } from \"@/registry/ui/checkbox\";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from \"@/registry/ui/dropdown-menu\";\n\ninterface Task {\n  id: number;\n  title: string;\n  description: string;\n  completed: boolean;\n  priority: \"high\" | \"medium\" | \"low\";\n  dueDate: string;\n  assignee: {\n    name: string;\n    avatar: string;\n  };\n  project: string;\n  tags: string[];\n  subtasks: number;\n  completedSubtasks: number;\n}\n\nexport interface List04Props {\n  className?: string;\n}\n\nconst content: {\n  tasks: Task[];\n  emptyState: { message: string; icon: LucideIcon };\n} = {\n  tasks: [\n    {\n      id: 1,\n      title: \"Implement user authentication system\",\n      description:\n        \"Set up JWT-based authentication with refresh tokens and role-based access control.\",\n      completed: false,\n      priority: \"high\" as const,\n      dueDate: \"2024-12-15\",\n      assignee: {\n        name: \"Sarah Johnson\",\n        avatar: \"https://randomuser.me/api/portraits/women/1.jpg\",\n      },\n      project: \"E-commerce Platform\",\n      tags: [\"Backend\", \"Security\"],\n      subtasks: 3,\n      completedSubtasks: 1,\n    },\n    {\n      id: 2,\n      title: \"Design mobile app wireframes\",\n      description:\n        \"Create low-fidelity wireframes for all main screens of the mobile application.\",\n      completed: true,\n      priority: \"medium\" as const,\n      dueDate: \"2024-12-10\",\n      assignee: {\n        name: \"Emily Rodriguez\",\n        avatar: \"https://randomuser.me/api/portraits/women/2.jpg\",\n      },\n      project: \"Mobile App\",\n      tags: [\"Design\", \"UX\"],\n      subtasks: 5,\n      completedSubtasks: 5,\n    },\n    {\n      id: 3,\n      title: \"Fix payment gateway integration bug\",\n      description:\n        \"Resolve timeout issues occurring during payment processing for certain card types.\",\n      completed: false,\n      priority: \"high\" as const,\n      dueDate: \"2024-12-12\",\n      assignee: {\n        name: \"Michael Chen\",\n        avatar: \"https://randomuser.me/api/portraits/men/3.jpg\",\n      },\n      project: \"E-commerce Platform\",\n      tags: [\"Bug Fix\", \"Payment\"],\n      subtasks: 2,\n      completedSubtasks: 0,\n    },\n    {\n      id: 4,\n      title: \"Update project documentation\",\n      description:\n        \"Review and update API documentation to reflect recent changes and new endpoints.\",\n      completed: false,\n      priority: \"low\" as const,\n      dueDate: \"2024-12-20\",\n      assignee: {\n        name: \"David Park\",\n        avatar: \"https://randomuser.me/api/portraits/men/4.jpg\",\n      },\n      project: \"Documentation\",\n      tags: [\"Documentation\", \"API\"],\n      subtasks: 4,\n      completedSubtasks: 2,\n    },\n    {\n      id: 5,\n      title: \"Conduct user testing session\",\n      description:\n        \"Organize and conduct usability testing with 10 participants for the new checkout flow.\",\n      completed: false,\n      priority: \"medium\" as const,\n      dueDate: \"2024-12-18\",\n      assignee: {\n        name: \"Lisa Thompson\",\n        avatar: \"https://randomuser.me/api/portraits/women/5.jpg\",\n      },\n      project: \"User Research\",\n      tags: [\"Testing\", \"UX\"],\n      subtasks: 6,\n      completedSubtasks: 3,\n    },\n    {\n      id: 6,\n      title: \"Optimize database queries\",\n      description:\n        \"Identify and optimize slow database queries to improve application performance.\",\n      completed: true,\n      priority: \"medium\" as const,\n      dueDate: \"2024-12-08\",\n      assignee: {\n        name: \"James Wilson\",\n        avatar: \"https://randomuser.me/api/portraits/men/6.jpg\",\n      },\n      project: \"Performance\",\n      tags: [\"Database\", \"Optimization\"],\n      subtasks: 3,\n      completedSubtasks: 3,\n    },\n  ],\n  emptyState: {\n    message: \"No tasks found\",\n    icon: CheckCircle2,\n  },\n};\n\nfunction getPriorityColor(priority: Task[\"priority\"]): string {\n  switch (priority) {\n    case \"high\":\n      return \"text-red-600 bg-red-100 dark:bg-red-900/20\";\n    case \"medium\":\n      return \"text-yellow-600 bg-yellow-100 dark:bg-yellow-900/20\";\n    case \"low\":\n      return \"text-green-600 bg-green-100 dark:bg-green-900/20\";\n    default:\n      return \"text-gray-600 bg-gray-100 dark:bg-gray-900/20\";\n  }\n}\n\nfunction getPriorityIcon(priority: Task[\"priority\"]): LucideIcon {\n  switch (priority) {\n    case \"high\":\n      return ArrowUp;\n    case \"medium\":\n      return Minus;\n    case \"low\":\n      return ArrowDown;\n    default:\n      return Minus;\n  }\n}\n\nfunction getDaysUntilDue(dueDate: string): number {\n  const today = new Date();\n  const due = new Date(dueDate);\n  const diffTime = due.getTime() - today.getTime();\n  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n  return diffDays;\n}\n\nfunction formatDueDate(daysUntilDue: number): string {\n  if (daysUntilDue === 0) return \"Due today\";\n  if (daysUntilDue === 1) return \"Due tomorrow\";\n  if (daysUntilDue > 0) return `Due in ${daysUntilDue} days`;\n  return `${Math.abs(daysUntilDue)} days overdue`;\n}\n\nexport function List04({ className }: List04Props) {\n  const [taskList, setTaskList] = useState(content.tasks);\n\n  const handleTaskToggle = (taskId: number) => {\n    const updatedTasks = taskList.map((task) =>\n      task.id === taskId ? { ...task, completed: !task.completed } : task,\n    );\n    setTaskList(updatedTasks);\n\n    const toggledTask = updatedTasks.find((task) => task.id === taskId);\n    if (toggledTask) {\n      console.log(\"Task toggled:\", {\n        taskId,\n        completed: toggledTask.completed,\n      });\n    }\n  };\n\n  const handleAssigneeClick = (\n    assignee: Task[\"assignee\"],\n    e: React.MouseEvent,\n  ) => {\n    e.stopPropagation();\n    console.log(\"Assignee clicked:\", assignee);\n  };\n\n  const handleActionClick = (action: string, task: Task) => {\n    console.log(`${action} clicked:`, task);\n  };\n\n  return (\n    <Card className={cn(\"w-full max-w-4xl mx-auto\", className)}>\n      <CardContent className=\"p-0\">\n        <div className=\"divide-y divide-border/50\">\n          {taskList.map((task) => {\n            const PriorityIcon = getPriorityIcon(task.priority);\n            const daysUntilDue = getDaysUntilDue(task.dueDate);\n            const isOverdue = daysUntilDue < 0 && !task.completed;\n\n            return (\n              <div\n                key={task.id}\n                className={cn(\n                  \"block p-4 hover:bg-muted/50 transition-colors\",\n                  task.completed && \"opacity-60\",\n                )}\n                data-testid={`task-${task.id}`}\n              >\n                <div className=\"flex items-start space-x-4\">\n                  <div className=\"flex-shrink-0 pt-1\">\n                    <Checkbox\n                      checked={task.completed}\n                      onCheckedChange={() => {\n                        handleTaskToggle(task.id);\n                      }}\n                      className=\"h-5 w-5\"\n                      onClick={(e) => e.stopPropagation()}\n                      data-testid={`task-checkbox-${task.id}`}\n                    />\n                  </div>\n\n                  <div className=\"flex-1 min-w-0 space-y-2\">\n                    <div className=\"flex items-start justify-between space-x-2\">\n                      <div className=\"flex-1 min-w-0\">\n                        <h3\n                          className={cn(\n                            \"text-sm font-medium leading-tight\",\n                            task.completed\n                              ? \"line-through text-muted-foreground\"\n                              : \"text-foreground\",\n                          )}\n                        >\n                          {task.title}\n                        </h3>\n                        {task.description && (\n                          <p className=\"text-sm text-muted-foreground mt-1 leading-relaxed\">\n                            {task.description}\n                          </p>\n                        )}\n                      </div>\n                      <div className=\"flex items-center space-x-2 flex-shrink-0 capitalize\">\n                        <Badge\n                          className={cn(\n                            getPriorityColor(task.priority),\n                            \"text-xs\",\n                          )}\n                          variant=\"secondary\"\n                          data-testid={`priority-badge-${task.id}`}\n                        >\n                          <PriorityIcon className=\"h-3 w-3 mr-1\" />\n                          {task.priority}\n                        </Badge>\n                        {isOverdue && (\n                          <Badge\n                            variant=\"destructive\"\n                            className=\"text-xs\"\n                            data-testid={`overdue-badge-${task.id}`}\n                          >\n                            <AlertCircle className=\"h-3 w-3 mr-1\" />\n                            Overdue\n                          </Badge>\n                        )}\n                      </div>\n                    </div>\n\n                    {task.subtasks && task.subtasks > 0 && (\n                      <div\n                        className=\"flex items-center space-x-2 text-xs text-muted-foreground\"\n                        data-testid={`subtasks-${task.id}`}\n                      >\n                        <CheckCircle2 className=\"h-3 w-3\" />\n                        <span>\n                          {task.completedSubtasks || 0}/{task.subtasks} subtasks\n                          completed\n                        </span>\n                      </div>\n                    )}\n\n                    {task.tags.length > 0 && (\n                      <div\n                        className=\"flex flex-wrap gap-1\"\n                        data-testid={`tags-${task.id}`}\n                      >\n                        {task.tags.map((tag) => (\n                          <Badge\n                            key={tag}\n                            variant=\"outline\"\n                            className=\"text-xs\"\n                          >\n                            {tag}\n                          </Badge>\n                        ))}\n                      </div>\n                    )}\n\n                    <div className=\"flex items-center justify-between pt-2\">\n                      <div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n                        <button\n                          type=\"button\"\n                          className=\"flex items-center space-x-1 cursor-pointer hover:bg-muted/50 rounded px-1 py-0.5 -mx-1 -my-0.5 transition-colors\"\n                          onClick={(e) => handleAssigneeClick(task.assignee, e)}\n                          data-testid={`assignee-${task.id}`}\n                        >\n                          <Avatar className=\"h-5 w-5\">\n                            <AvatarImage\n                              src={task.assignee.avatar}\n                              alt={task.assignee.name}\n                            />\n                            <AvatarFallback className=\"text-xs\">\n                              {task.assignee.name\n                                .split(\" \")\n                                .map((n) => n[0])\n                                .join(\"\")}\n                            </AvatarFallback>\n                          </Avatar>\n                          <span>{task.assignee.name}</span>\n                        </button>\n                        <div\n                          className=\"flex items-center space-x-1\"\n                          data-testid={`due-date-${task.id}`}\n                        >\n                          <Calendar className=\"h-3 w-3\" />\n                          <span className={cn(isOverdue && \"text-destructive\")}>\n                            {formatDueDate(daysUntilDue)}\n                          </span>\n                        </div>\n                        <Badge variant=\"outline\" className=\"text-xs\">\n                          {task.project}\n                        </Badge>\n                      </div>\n\n                      <div>\n                        <DropdownMenu>\n                          <DropdownMenuTrigger asChild>\n                            <Button\n                              variant=\"ghost\"\n                              size=\"icon\"\n                              className=\"h-6 w-6\"\n                              data-testid={`task-actions-${task.id}`}\n                            >\n                              <MoreHorizontal className=\"h-3 w-3\" />\n                            </Button>\n                          </DropdownMenuTrigger>\n                          <DropdownMenuContent\n                            align=\"end\"\n                            data-testid={`task-dropdown-${task.id}`}\n                          >\n                            <DropdownMenuItem\n                              onClick={() => {\n                                handleActionClick(\"edit\", task);\n                              }}\n                            >\n                              Edit Task\n                            </DropdownMenuItem>\n                            <DropdownMenuItem\n                              onClick={() => {\n                                handleActionClick(\"duplicate\", task);\n                              }}\n                            >\n                              Duplicate\n                            </DropdownMenuItem>\n                            <DropdownMenuItem\n                              onClick={() => {\n                                handleActionClick(\"change-priority\", task);\n                              }}\n                            >\n                              Change Priority\n                            </DropdownMenuItem>\n                            <DropdownMenuItem\n                              onClick={() => {\n                                handleActionClick(\"assign\", task);\n                              }}\n                            >\n                              Assign to...\n                            </DropdownMenuItem>\n                            <DropdownMenuSeparator />\n                            <DropdownMenuItem\n                              className=\"text-destructive\"\n                              onClick={() => {\n                                handleActionClick(\"delete\", task);\n                              }}\n                            >\n                              Delete Task\n                            </DropdownMenuItem>\n                          </DropdownMenuContent>\n                        </DropdownMenu>\n                      </div>\n                    </div>\n                  </div>\n                </div>\n              </div>\n            );\n          })}\n        </div>\n\n        {taskList.length === 0 && (\n          <div className=\"p-8 text-center\" data-testid=\"empty-state\">\n            <content.emptyState.icon className=\"h-12 w-12 text-muted-foreground mx-auto mb-4\" />\n            <p className=\"text-muted-foreground\">\n              {content.emptyState.message}\n            </p>\n          </div>\n        )}\n      </CardContent>\n    </Card>\n  );\n}\n","type":"registry:component"},{"path":"src/registry/lib/utils.ts","content":"import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n","type":"registry:lib"}]}