From 37b183f4bf1139e9b52caa13d0abfaf2e8be9d90 Mon Sep 17 00:00:00 2001 From: Zachary Quintana Date: Mon, 1 Dec 2025 13:00:33 -0700 Subject: [PATCH 1/9] feat: install @dnd-kit packages for drag-and-drop functionality --- package-lock.json | 56 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +++ 2 files changed, 59 insertions(+) diff --git a/package-lock.json b/package-lock.json index 1f47f6d..4b35f15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "temp-next", "version": "0.1.0", "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@reduxjs/toolkit": "^2.9.1", "@types/uuid": "^10.0.0", "framer-motion": "^12.23.24", @@ -697,6 +700,59 @@ "node": ">=18" } }, + "node_modules/@dnd-kit/accessibility": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", + "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/core": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", + "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", + "license": "MIT", + "dependencies": { + "@dnd-kit/accessibility": "^3.1.1", + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/sortable": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz", + "integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==", + "license": "MIT", + "dependencies": { + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@dnd-kit/core": "^6.3.0", + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/utilities": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz", + "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/@emnapi/core": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.6.0.tgz", diff --git a/package.json b/package.json index cb1a48c..0c7ee6b 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,9 @@ "test:coverage": "jest --coverage" }, "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@reduxjs/toolkit": "^2.9.1", "@types/uuid": "^10.0.0", "framer-motion": "^12.23.24", From 6014da7e4000da521234f8eb2dbc0b0e765cf416 Mon Sep 17 00:00:00 2001 From: Zachary Quintana Date: Mon, 1 Dec 2025 13:00:52 -0700 Subject: [PATCH 2/9] feat: add order field to Task interface for custom ordering --- src/lib/types/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts index 9f8c757..921431f 100644 --- a/src/lib/types/index.ts +++ b/src/lib/types/index.ts @@ -17,6 +17,7 @@ export interface Task { dueDate: string | null; createdAt: string; updatedAt: string; + order?: number; // Global position for custom ordering (not per-priority) } export interface RootState { From 6eeff493af5995c3f807117955f782de4f928dd2 Mon Sep 17 00:00:00 2001 From: Zachary Quintana Date: Mon, 1 Dec 2025 13:01:28 -0700 Subject: [PATCH 3/9] feat: add Redux actions for global task reordering and priority movement --- src/lib/features/tasksSlice.ts | 123 +++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/src/lib/features/tasksSlice.ts b/src/lib/features/tasksSlice.ts index 53dbeb6..7cec828 100644 --- a/src/lib/features/tasksSlice.ts +++ b/src/lib/features/tasksSlice.ts @@ -55,6 +55,124 @@ export const tasksSlice = createSlice({ state.loading = false; state.error = null; }, + reorderTasks: ( + state, + action: PayloadAction<{ activeId: string; overId: string }> + ) => { + const { activeId, overId } = action.payload; + const tasks = [...state.items]; + const activeIndex = tasks.findIndex((t) => t.id === activeId); + const overIndex = tasks.findIndex((t) => t.id === overId); + + if (activeIndex === -1 || overIndex === -1 || activeIndex === overIndex) { + return; + } + + // Sort tasks by order (or createdAt if no order) + const sortedTasks = [...tasks].sort((a, b) => { + const aOrder = a.order ?? Infinity; + const bOrder = b.order ?? Infinity; + if (aOrder !== bOrder) return aOrder - bOrder; + return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(); + }); + + // Find indices in sorted array + const sortedActiveIndex = sortedTasks.findIndex((t) => t.id === activeId); + const sortedOverIndex = sortedTasks.findIndex((t) => t.id === overId); + + if (sortedActiveIndex === -1 || sortedOverIndex === -1) return; + + // Remove active task and insert at new position + const [movedTask] = sortedTasks.splice(sortedActiveIndex, 1); + sortedTasks.splice(sortedOverIndex, 0, movedTask); + + // Update order values for all tasks + sortedTasks.forEach((task, index) => { + const stateTask = state.items.find((t) => t.id === task.id); + if (stateTask) { + stateTask.order = index; + stateTask.updatedAt = new Date().toISOString(); + } + }); + }, + moveTaskToPriority: ( + state, + action: PayloadAction<{ taskId: string; newPriority: PriorityLevel; newOrder?: number }> + ) => { + const { taskId, newPriority, newOrder } = action.payload; + const task = state.items.find((t) => t.id === taskId); + if (!task) return; + + const oldPriority = task.priority; + task.priority = newPriority; + task.updatedAt = new Date().toISOString(); + + // Get all tasks sorted by order + const sortedTasks = [...state.items].sort((a, b) => { + const aOrder = a.order ?? Infinity; + const bOrder = b.order ?? Infinity; + if (aOrder !== bOrder) return aOrder - bOrder; + return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(); + }); + + // Find the task in sorted array + const taskIndex = sortedTasks.findIndex((t) => t.id === taskId); + if (taskIndex === -1) return; + + // Remove task from its current position + sortedTasks.splice(taskIndex, 1); + + // If newOrder is provided, insert at that position; otherwise find appropriate position + if (newOrder !== undefined) { + sortedTasks.splice(newOrder, 0, task); + } else { + // Find position after last task with same priority + const lastSamePriorityIndex = sortedTasks + .map((t, idx) => ({ task: t, idx })) + .filter(({ task: t }) => t.priority === newPriority) + .pop()?.idx; + const insertIndex = lastSamePriorityIndex !== undefined ? lastSamePriorityIndex + 1 : sortedTasks.length; + sortedTasks.splice(insertIndex, 0, task); + } + + // Update order for all tasks + sortedTasks.forEach((t, index) => { + const stateTask = state.items.find((item) => item.id === t.id); + if (stateTask) { + stateTask.order = index; + stateTask.updatedAt = new Date().toISOString(); + } + }); + }, + setTaskOrder: ( + state, + action: PayloadAction<{ taskId: string; order: number }> + ) => { + const { taskId, order } = action.payload; + const task = state.items.find((t) => t.id === taskId); + if (task) { + task.order = order; + task.updatedAt = new Date().toISOString(); + } + }, + reorderMultipleTasks: ( + state, + action: PayloadAction> + ) => { + action.payload.forEach(({ taskId, order }) => { + const task = state.items.find((t) => t.id === taskId); + if (task) { + task.order = order; + task.updatedAt = new Date().toISOString(); + } + }); + }, + clearTaskOrder: (state) => { + state.items.forEach((task) => { + delete task.order; + task.updatedAt = new Date().toISOString(); + }); + }, }, }); @@ -68,5 +186,10 @@ export const { setLoading, setError, clearTasks, + reorderTasks, + moveTaskToPriority, + setTaskOrder, + reorderMultipleTasks, + clearTaskOrder, } = tasksSlice.actions; export default tasksSlice.reducer; From 01e707911c19cd84e84fb512e6002ca53e797a94 Mon Sep 17 00:00:00 2001 From: Zachary Quintana Date: Mon, 1 Dec 2025 13:02:02 -0700 Subject: [PATCH 4/9] feat: add order field handling and migration in API service --- src/lib/services/localApi.ts | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/lib/services/localApi.ts b/src/lib/services/localApi.ts index 25110c6..3707d91 100644 --- a/src/lib/services/localApi.ts +++ b/src/lib/services/localApi.ts @@ -8,6 +8,7 @@ import { toggleTask, updateTaskDueDate, updateTaskPriority, + setTaskOrder, } from "../features/tasksSlice"; import { saveState, loadState } from "../utils/localStorage"; @@ -50,6 +51,32 @@ export const localApi = createApi({ } ); + // Migrate tasks without order field: assign default order based on current sort + const tasksNeedingOrder = migratedTasks.filter((task) => task.order === undefined); + if (tasksNeedingOrder.length > 0) { + // Sort all tasks by current sort order (priority → dueDate → createdAt) + const sorted = [...migratedTasks].sort((a, b) => { + // First by priority + if (a.priority !== b.priority) { + return a.priority - b.priority; + } + // Then by due date + if (!a.dueDate && !b.dueDate) { + return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(); + } + if (!a.dueDate) return 1; + if (!b.dueDate) return -1; + return new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime(); + }); + + // Assign order values based on sorted position + sorted.forEach((task, index) => { + if (task.order === undefined) { + task.order = index; + } + }); + } + dispatch(setTasks(migratedTasks)); return { data: migratedTasks }; }, @@ -96,6 +123,11 @@ export const localApi = createApi({ updateTaskPriority({ id: update.id, priority: update.priority! }) ); } + if ("order" in update && update.order !== undefined) { + dispatch( + setTaskOrder({ taskId: update.id, order: update.order }) + ); + } const state = getState(); saveState(state); const updatedTask = { From 6cb3e994b3a4d0b9c18c98c852a6b65ae813d6af Mon Sep 17 00:00:00 2001 From: Zachary Quintana Date: Mon, 1 Dec 2025 13:02:35 -0700 Subject: [PATCH 5/9] feat: make TaskItem draggable with visual feedback --- src/components/tasks/TaskItem.tsx | 56 ++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/components/tasks/TaskItem.tsx b/src/components/tasks/TaskItem.tsx index 4bb8682..574de22 100644 --- a/src/components/tasks/TaskItem.tsx +++ b/src/components/tasks/TaskItem.tsx @@ -11,13 +11,16 @@ import { formatDateForDisplay } from "@/lib/utils/dateFormatting"; import { PRIORITY_LEVELS, getPriorityStyles } from "@/lib/utils/priorityUtils"; import { highlightText } from "@/lib/utils/searchUtils"; import toast from "react-hot-toast"; +import { useSortable } from "@dnd-kit/sortable"; +import { CSS } from "@dnd-kit/utilities"; interface TaskItemProps { task: Task; searchQuery?: string; + isDragEnabled?: boolean; } -export function TaskItem({ task, searchQuery }: TaskItemProps) { +export function TaskItem({ task, searchQuery, isDragEnabled = false }: TaskItemProps) { const [updateTask] = useUpdateTaskMutation(); const [deleteTask] = useDeleteTaskMutation(); const [isUpdating, setIsUpdating] = useState(false); @@ -25,6 +28,24 @@ export function TaskItem({ task, searchQuery }: TaskItemProps) { const [isEditingDate, setIsEditingDate] = useState(false); const [editedDate, setEditedDate] = useState(task.dueDate || ""); + const { + attributes, + listeners, + setNodeRef, + transform, + transition, + isDragging, + } = useSortable({ + id: task.id, + disabled: !isDragEnabled, + }); + + const style = { + transform: CSS.Transform.toString(transform), + transition, + opacity: isDragging ? 0.5 : 1, + }; + const handleToggle = async () => { try { setIsUpdating(true); @@ -130,12 +151,39 @@ export function TaskItem({ task, searchQuery }: TaskItemProps) { return (
+ {isDragEnabled && ( +
+ + + + + + + + +
+ )}
{isUpdating ? (
From 93e476367d6570fbf2566c33ee19c132e5c5549b Mon Sep 17 00:00:00 2001 From: Zachary Quintana Date: Mon, 1 Dec 2025 13:03:40 -0700 Subject: [PATCH 6/9] feat: implement drag-and-drop reordering with toggle in TaskList --- src/components/tasks/TaskList.tsx | 258 +++++++++++++++++++++++------- 1 file changed, 203 insertions(+), 55 deletions(-) diff --git a/src/components/tasks/TaskList.tsx b/src/components/tasks/TaskList.tsx index 911d2ea..bb98186 100644 --- a/src/components/tasks/TaskList.tsx +++ b/src/components/tasks/TaskList.tsx @@ -1,9 +1,9 @@ "use client"; import { useState, useMemo } from "react"; -import { useSelector } from "react-redux"; -import { RootState, PriorityLevel } from "@/lib/types"; -import { useGetTasksQuery } from "@/lib/services/localApi"; +import { useSelector, useDispatch } from "react-redux"; +import { RootState, PriorityLevel, Task } from "@/lib/types"; +import { useGetTasksQuery, useUpdateTaskMutation } from "@/lib/services/localApi"; import { TaskItem } from "./TaskItem"; import { AddTaskForm } from "./AddTaskForm"; import { TaskSearch } from "./TaskSearch"; @@ -16,15 +16,43 @@ import { } from "@/lib/utils/priorityUtils"; import { searchTasks } from "@/lib/utils/searchUtils"; import { motion, AnimatePresence } from "framer-motion"; +import { + DndContext, + closestCenter, + KeyboardSensor, + PointerSensor, + useSensor, + useSensors, + DragEndEvent, + DragStartEvent, +} from "@dnd-kit/core"; +import { + arrayMove, + SortableContext, + sortableKeyboardCoordinates, + verticalListSortingStrategy, +} from "@dnd-kit/sortable"; +import { reorderTasks, moveTaskToPriority, clearTaskOrder, reorderMultipleTasks } from "@/lib/features/tasksSlice"; export function TaskList() { const { data: tasks = [], isLoading, error } = useGetTasksQuery(); const { isAuthenticated } = useSelector((state: RootState) => state.user); + const dispatch = useDispatch(); + const [updateTask] = useUpdateTaskMutation(); const [priorityFilter, setPriorityFilter] = useState<"all" | PriorityLevel>( "all" ); const [searchQuery, setSearchQuery] = useState(""); + const [useCustomOrder, setUseCustomOrder] = useState(false); + const [activeId, setActiveId] = useState(null); + + const sensors = useSensors( + useSensor(PointerSensor), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }) + ); const filteredAndSortedTasks = useMemo(() => { let filteredTasks = [...tasks]; @@ -39,21 +67,112 @@ export function TaskList() { }); } - return filteredTasks.sort((a, b) => { - if (a.priority !== b.priority) { - return a.priority - b.priority; - } - - if (!a.dueDate && !b.dueDate) { - return ( - new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime() - ); - } - if (!a.dueDate) return 1; - if (!b.dueDate) return -1; - return new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime(); + if (useCustomOrder) { + // Sort by global order field (allowing items to be positioned above/below items of different priorities) + return filteredTasks.sort((a, b) => { + const aOrder = a.order ?? Infinity; + const bOrder = b.order ?? Infinity; + if (aOrder !== bOrder) { + return aOrder - bOrder; + } + // Fallback to createdAt if no order + return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(); + }); + } else { + // Auto sort: priority → due date → created date + return filteredTasks.sort((a, b) => { + if (a.priority !== b.priority) { + return a.priority - b.priority; + } + + if (!a.dueDate && !b.dueDate) { + return ( + new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime() + ); + } + if (!a.dueDate) return 1; + if (!b.dueDate) return -1; + return new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime(); + }); + } + }, [tasks, priorityFilter, searchQuery, useCustomOrder]); + + const handleDragStart = (event: DragStartEvent) => { + setActiveId(event.active.id as string); + }; + + const handleDragEnd = async (event: DragEndEvent) => { + const { active, over } = event; + setActiveId(null); + + if (!over || active.id === over.id) { + return; + } + + const activeTask = tasks.find((t) => t.id === active.id); + if (!activeTask) return; + + const overTask = tasks.find((t) => t.id === over.id); + if (!overTask) return; + + // Get all tasks sorted by current order + const sortedTasks = [...tasks].sort((a, b) => { + const aOrder = a.order ?? Infinity; + const bOrder = b.order ?? Infinity; + if (aOrder !== bOrder) return aOrder - bOrder; + return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(); }); - }, [tasks, priorityFilter, searchQuery]); + + const oldIndex = sortedTasks.findIndex((t) => t.id === active.id); + const newIndex = sortedTasks.findIndex((t) => t.id === over.id); + + if (oldIndex === -1 || newIndex === -1 || oldIndex === newIndex) { + return; + } + + // Reorder tasks + const reordered = arrayMove(sortedTasks, oldIndex, newIndex); + + // Update priorities if dragging across priority boundaries + if (activeTask.priority !== overTask.priority) { + // Update the dragged task's priority to match the target + dispatch( + moveTaskToPriority({ + taskId: active.id as string, + newPriority: overTask.priority, + newOrder: newIndex, + }) + ); + await updateTask({ + id: active.id as string, + priority: overTask.priority, + order: newIndex, + }).unwrap(); + } + + // Update order for all tasks + const orderUpdates = reordered.map((task, index) => ({ + taskId: task.id, + order: index, + })); + + dispatch(reorderMultipleTasks(orderUpdates)); + + // Persist updates + await Promise.all( + orderUpdates.map(({ taskId, order }) => + updateTask({ id: taskId, order }).unwrap() + ) + ); + }; + + const handleToggleCustomOrder = () => { + if (useCustomOrder) { + // Switching to auto sort - clear custom order + dispatch(clearTaskOrder()); + } + setUseCustomOrder(!useCustomOrder); + }; if (!isAuthenticated) { return ( @@ -89,11 +208,24 @@ export function TaskList() { {tasks.length > 0 && (
-
- +
+
+ +
+
@@ -205,43 +337,59 @@ export function TaskList() {
)} -
- - {filteredAndSortedTasks.length === 0 ? ( - -

- {tasks.length === 0 - ? "No tasks yet" - : "No tasks match the current filter"} -

-

- {tasks.length === 0 - ? "Add your first task using the form above!" - : searchQuery.trim() - ? "Try adjusting your search or priority filter." - : "Try changing the priority filter above."} -

-
- ) : ( - filteredAndSortedTasks.map((task) => ( + +
+ + {filteredAndSortedTasks.length === 0 ? ( - +

+ {tasks.length === 0 + ? "No tasks yet" + : "No tasks match the current filter"} +

+

+ {tasks.length === 0 + ? "Add your first task using the form above!" + : searchQuery.trim() + ? "Try adjusting your search or priority filter." + : "Try changing the priority filter above."} +

- )) - )} -
-
+ ) : ( + t.id)} + strategy={verticalListSortingStrategy} + > + {filteredAndSortedTasks.map((task) => ( + + + + ))} + + )} +
+
+
); } From 97a45dc8afe08fcb77ee8aad20066742e426e069 Mon Sep 17 00:00:00 2001 From: Zachary Quintana Date: Mon, 1 Dec 2025 13:04:27 -0700 Subject: [PATCH 7/9] feat: enhance drag-and-drop visual feedback and cross-priority animations --- src/components/tasks/TaskList.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/components/tasks/TaskList.tsx b/src/components/tasks/TaskList.tsx index bb98186..cdd1130 100644 --- a/src/components/tasks/TaskList.tsx +++ b/src/components/tasks/TaskList.tsx @@ -25,6 +25,7 @@ import { useSensors, DragEndEvent, DragStartEvent, + DragOverlay, } from "@dnd-kit/core"; import { arrayMove, @@ -389,6 +390,23 @@ export function TaskList() { )}
+ + {activeId ? ( + (() => { + const activeTask = tasks.find((t) => t.id === activeId); + if (!activeTask) return null; + return ( +
+ +
+ ); + })() + ) : null} +
); From 23b1b79fa2e70f89d16269a992b64cb66b914c29 Mon Sep 17 00:00:00 2001 From: Zachary Quintana Date: Mon, 1 Dec 2025 13:06:28 -0700 Subject: [PATCH 8/9] fix: always update task priority to match target when dragging --- src/components/tasks/TaskList.tsx | 47 ++++++++++++++++--------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/components/tasks/TaskList.tsx b/src/components/tasks/TaskList.tsx index cdd1130..d706513 100644 --- a/src/components/tasks/TaskList.tsx +++ b/src/components/tasks/TaskList.tsx @@ -134,24 +134,20 @@ export function TaskList() { // Reorder tasks const reordered = arrayMove(sortedTasks, oldIndex, newIndex); - // Update priorities if dragging across priority boundaries - if (activeTask.priority !== overTask.priority) { - // Update the dragged task's priority to match the target - dispatch( - moveTaskToPriority({ - taskId: active.id as string, - newPriority: overTask.priority, - newOrder: newIndex, - }) - ); - await updateTask({ - id: active.id as string, - priority: overTask.priority, - order: newIndex, - }).unwrap(); - } + // Always update the dragged task's priority to match the target task's priority + // This ensures the task takes on the priority of where it's dropped + const newPriority = overTask.priority; + + // Update priority and order for the active task + dispatch( + moveTaskToPriority({ + taskId: active.id as string, + newPriority: newPriority, + newOrder: newIndex, + }) + ); - // Update order for all tasks + // Update order for all tasks (including the active one) const orderUpdates = reordered.map((task, index) => ({ taskId: task.id, order: index, @@ -159,12 +155,19 @@ export function TaskList() { dispatch(reorderMultipleTasks(orderUpdates)); - // Persist updates - await Promise.all( - orderUpdates.map(({ taskId, order }) => + // Persist all updates + await Promise.all([ + // Update the active task with new priority and order + updateTask({ + id: active.id as string, + priority: newPriority, + order: newIndex, + }).unwrap(), + // Update order for all tasks + ...orderUpdates.map(({ taskId, order }) => updateTask({ id: taskId, order }).unwrap() - ) - ); + ), + ]); }; const handleToggleCustomOrder = () => { From 71b4d935f956055dd332120064374392533fc1bb Mon Sep 17 00:00:00 2001 From: Zachary Quintana Date: Mon, 1 Dec 2025 13:07:34 -0700 Subject: [PATCH 9/9] fix: keep task priority unchanged when reordering --- src/components/tasks/TaskList.tsx | 32 ++++++------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/src/components/tasks/TaskList.tsx b/src/components/tasks/TaskList.tsx index d706513..91347f5 100644 --- a/src/components/tasks/TaskList.tsx +++ b/src/components/tasks/TaskList.tsx @@ -134,20 +134,7 @@ export function TaskList() { // Reorder tasks const reordered = arrayMove(sortedTasks, oldIndex, newIndex); - // Always update the dragged task's priority to match the target task's priority - // This ensures the task takes on the priority of where it's dropped - const newPriority = overTask.priority; - - // Update priority and order for the active task - dispatch( - moveTaskToPriority({ - taskId: active.id as string, - newPriority: newPriority, - newOrder: newIndex, - }) - ); - - // Update order for all tasks (including the active one) + // Update order for all tasks (priority remains unchanged) const orderUpdates = reordered.map((task, index) => ({ taskId: task.id, order: index, @@ -155,19 +142,12 @@ export function TaskList() { dispatch(reorderMultipleTasks(orderUpdates)); - // Persist all updates - await Promise.all([ - // Update the active task with new priority and order - updateTask({ - id: active.id as string, - priority: newPriority, - order: newIndex, - }).unwrap(), - // Update order for all tasks - ...orderUpdates.map(({ taskId, order }) => + // Persist order updates (priority is not changed) + await Promise.all( + orderUpdates.map(({ taskId, order }) => updateTask({ id: taskId, order }).unwrap() - ), - ]); + ) + ); }; const handleToggleCustomOrder = () => {