"use client"; import type { DragEndEvent, DragStartEvent } from "@dnd-kit/core"; import { closestCenter, DndContext, DragOverlay, KeyboardSensor, PointerSensor, useSensor, useSensors, } from "@dnd-kit/core"; import { arrayMove, SortableContext, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy, } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import { Check, Edit, GripVertical, MoreVertical, Plus, Trash2, X, } from "lucide-react"; import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; import { Item, ItemActions, ItemContent, ItemGroup, ItemMedia, ItemTitle, } from "@/components/ui/item"; import { cn } from "@/lib/utils"; interface Todo { id: string; title: string; completed: boolean; } interface Todo5Props { heading?: string; description?: string; addTaskLabel?: string; taskPlaceholder?: string; cancelLabel?: string; submitLabel?: string; editLabel?: string; deleteLabel?: string; saveEditLabel?: string; cancelEditLabel?: string; moreActionsLabel?: string; editFieldLabel?: string; deleteDialogTitle?: string; deleteDialogDescription?: string; deleteConfirmLabel?: string; initialTodos?: Todo[]; className?: string; } const defaultTodos: Todo[] = [ { id: "1", title: "تکمیل مستندات فنی پروژه", completed: false, }, { id: "2", title: "بررسی و تأیید طراحی رابط کاربری", completed: false, }, { id: "3", title: "آماده‌سازی گزارش هفتگی", completed: false, }, ]; interface SortableTodoItemProps { todo: Todo; onToggle: (id: string) => void; editingTodo: string | null; editTitle: string; onStartEdit: (todo: Todo) => void; onSaveEdit: () => void; onCancelEdit: () => void; onEditTitleChange: (title: string) => void; onDeleteClick: (id: string) => void; editLabel: string; deleteLabel: string; saveEditLabel: string; cancelEditLabel: string; moreActionsLabel: string; editFieldLabel: string; } const SortableTodoItem = ({ todo, onToggle, editingTodo, editTitle, onStartEdit, onSaveEdit, onCancelEdit, onEditTitleChange, onDeleteClick, editLabel, deleteLabel, saveEditLabel, cancelEditLabel, moreActionsLabel, editFieldLabel, }: SortableTodoItemProps) => { const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id: todo.id }); const style = { transform: CSS.Translate.toString(transform), transition, opacity: isDragging ? 0.5 : 1, }; return (
onToggle(todo.id)} >
onToggle(todo.id)} onClick={(e) => e.stopPropagation()} aria-label={ todo.completed ? `علامت‌گذاری «${todo.title}» به‌عنوان انجام‌نشده` : `علامت‌گذاری «${todo.title}» به‌عنوان انجام‌شده` } />
{editingTodo === todo.id ? ( onEditTitleChange(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { onSaveEdit(); } if (e.key === "Escape") { onCancelEdit(); } }} onClick={(e) => e.stopPropagation()} className="text-base font-medium" autoFocus aria-label={editFieldLabel} /> ) : ( {todo.title} )} {editingTodo === todo.id ? (
) : ( e.stopPropagation()} > { e.stopPropagation(); onStartEdit(todo); }} > {editLabel} { e.stopPropagation(); onDeleteClick(todo.id); }} > {deleteLabel} )}
); }; const Todo5 = ({ heading = "مدیریت وظایف با ویرایش و حذف", description = "وظیفه جدید اضافه کنید، ترتیب را تغییر دهید، ویرایش کنید یا حذف کنید.", addTaskLabel = "افزودن وظیفه جدید", taskPlaceholder = "عنوان وظیفه", cancelLabel = "انصراف", submitLabel = "افزودن", editLabel = "ویرایش", deleteLabel = "حذف", saveEditLabel = "ذخیره", cancelEditLabel = "لغو", moreActionsLabel = "گزینه‌های بیشتر", editFieldLabel = "ویرایش عنوان وظیفه", deleteDialogTitle = "حذف وظیفه؟", deleteDialogDescription = "این وظیفه برای همیشه حذف می‌شود و قابل بازگشت نیست.", deleteConfirmLabel = "حذف", initialTodos = defaultTodos, className, }: Todo5Props) => { const [todos, setTodos] = useState(initialTodos); const [isFormExpanded, setIsFormExpanded] = useState(false); const [newTaskTitle, setNewTaskTitle] = useState(""); const [editingTodo, setEditingTodo] = useState(null); const [editTitle, setEditTitle] = useState(""); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [todoToDelete, setTodoToDelete] = useState(null); const [activeTodo, setActiveTodo] = useState(null); const sensors = useSensors( useSensor(PointerSensor), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates, }), ); const toggleTodo = (id: string) => { setTodos((prevTodos) => prevTodos.map((todo) => todo.id === id ? { ...todo, completed: !todo.completed } : todo, ), ); }; const handleAddTask = () => { if (newTaskTitle.trim()) { const newTodo: Todo = { id: Date.now().toString(), title: newTaskTitle.trim(), completed: false, }; setTodos((prevTodos) => [...prevTodos, newTodo]); setNewTaskTitle(""); setIsFormExpanded(false); } }; const handleStartEdit = (todo: Todo) => { setEditingTodo(todo.id); setEditTitle(todo.title); }; const handleSaveEdit = () => { if (editingTodo && editTitle.trim()) { setTodos((prevTodos) => prevTodos.map((todo) => todo.id === editingTodo ? { ...todo, title: editTitle.trim() } : todo, ), ); setEditingTodo(null); setEditTitle(""); } }; const handleCancelEdit = () => { setEditingTodo(null); setEditTitle(""); }; const handleDeleteClick = (id: string) => { setTodoToDelete(id); setDeleteDialogOpen(true); }; const handleDeleteConfirm = () => { if (todoToDelete) { setTodos((prevTodos) => prevTodos.filter((todo) => todo.id !== todoToDelete), ); setDeleteDialogOpen(false); setTodoToDelete(null); } }; const handleDragStart = (event: DragStartEvent) => { const { active } = event; const todo = todos.find((t) => t.id === active.id); setActiveTodo(todo || null); }; const handleDragEnd = (event: DragEndEvent) => { const { active, over } = event; if (over && active.id !== over.id) { setTodos((items) => { const oldIndex = items.findIndex((item) => item.id === active.id); const newIndex = items.findIndex((item) => item.id === over.id); return arrayMove(items, oldIndex, newIndex); }); } setActiveTodo(null); }; return (

{heading}

{description}

{!isFormExpanded ? ( ) : (
setNewTaskTitle(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter" && newTaskTitle.trim()) { handleAddTask(); } if (e.key === "Escape") { setNewTaskTitle(""); setIsFormExpanded(false); } }} className="text-base font-medium" aria-label={taskPlaceholder} />
)} t.id)} strategy={verticalListSortingStrategy} > {todos.map((todo) => ( ))}
{activeTodo ? (
{activeTodo.title}
) : null}
{deleteDialogTitle} {deleteDialogDescription}
); }; export { Todo5 };