From a88dec045a1551f25ba3dc54eb3d032504fa829d Mon Sep 17 00:00:00 2001 From: Skotomogilnik Date: Tue, 22 Sep 2026 04:53:32 +0300 Subject: [PATCH] Fix moveProjects leaving the UI and disk state inconsistent when a project update or reorder operation fails midway. Capture the previous projects state before applying the optimistic update. Roll back the optimistic UI state when an API operation fails. Refresh projects from the backend after a failure to restore the actual persisted state. Re-throw the error so existing error handling can handle the failure. --- src/hooks/useProjects.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/hooks/useProjects.ts b/src/hooks/useProjects.ts index 4125f240..95809344 100644 --- a/src/hooks/useProjects.ts +++ b/src/hooks/useProjects.ts @@ -99,6 +99,7 @@ export function useProjects() { async (ids: string[], category: string, destOrderedIds: string[]) => { if (ids.length === 0) return const moving = new Set(ids) + const snapshot = Array.isArray(projects) ? [...projects] : null setData((prev) => { if (!Array.isArray(prev)) return prev const rank = new Map(destOrderedIds.map((pid, i) => [pid, i])) @@ -116,12 +117,18 @@ export function useProjects() { return p }) }) - for (const id of ids) { - await api.updateProject(id, { category }) + try { + for (const id of ids) { + await api.updateProject(id, { category }) + } + await api.reorderProjects(destOrderedIds) + } catch (e) { + if (snapshot) setData(snapshot) + await refresh() + throw e } - await api.reorderProjects(destOrderedIds) }, - [setData], + [projects, refresh, setData], ) const reorder = useCallback(async (orderedIds: string[]) => {