From 0a84bf3114b539ee22a56c2679d12286e229ee45 Mon Sep 17 00:00:00 2001 From: mARTin Date: Mon, 6 Apr 2026 18:07:03 +0200 Subject: [PATCH] feat: preserve tabs on sync disconnect/reconnect Disconnecting a synced list (Google/Outlook/Synology) now uses a soft-disconnect: tasks are soft-deleted and the external link is cleared, but the SomedayList record is kept with its tab assignment intact. When the user reconnects, the import route finds the list by title, re-links the external provider, and restores tasks (clearing deletedAt). Tabs survive the full disconnect/reconnect cycle without the user needing to drag lists back to tabs. Also clears deletedAt on task re-import so previously disconnected tasks become visible again on reconnect. v1.89.0 --- package.json | 2 +- src/app/api/someday-lists/route.ts | 12 ++++++++++++ src/app/api/tasks/import/route.ts | 3 ++- src/components/WeeklyView.tsx | 10 +++++++--- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 786c452..0182eb5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "my-weekly-todo-list", - "version": "1.88.2", + "version": "1.89.0", "description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view", "main": "index.js", "scripts": { diff --git a/src/app/api/someday-lists/route.ts b/src/app/api/someday-lists/route.ts index 54de06e..e103c43 100644 --- a/src/app/api/someday-lists/route.ts +++ b/src/app/api/someday-lists/route.ts @@ -121,6 +121,8 @@ export async function DELETE(request: NextRequest) { const { searchParams } = new URL(request.url); const id = searchParams.get('id'); + // tasksOnly=true: soft-disconnect (keep list record with tab, just remove tasks + external link) + const tasksOnly = searchParams.get('tasksOnly') === 'true'; if (!id) { return NextResponse.json( @@ -147,6 +149,16 @@ export async function DELETE(request: NextRequest) { data: { deletedAt: new Date(), somedayListId: null } }); + if (tasksOnly) { + // Soft-disconnect: keep list record (preserves tab assignment) but clear external link + await prisma.somedayList.update({ + where: { id }, + data: { externalId: null, externalProvider: null, lastSyncedAt: null } + }); + notifyUser(userId, "list-changed", { action: "disconnected" }); + return NextResponse.json({ success: true, kept: true }); + } + await prisma.somedayList.delete({ where: { id } }); diff --git a/src/app/api/tasks/import/route.ts b/src/app/api/tasks/import/route.ts index 9dcf8db..9dc30b0 100644 --- a/src/app/api/tasks/import/route.ts +++ b/src/app/api/tasks/import/route.ts @@ -293,7 +293,8 @@ export async function POST(req: NextRequest) { where: { id: existingTask.id }, data: { somedayListId: somedayList.id, - lastSyncedAt: new Date() + lastSyncedAt: new Date(), + deletedAt: null, // clear soft-delete from a previous disconnect } }); externalToLocalId.set(task.externalId, existingTask.id); diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx index 9cc5970..29e8950 100644 --- a/src/components/WeeklyView.tsx +++ b/src/components/WeeklyView.tsx @@ -3672,10 +3672,13 @@ export default function WeeklyView() { ); if (!existing) { setUnsyncConfirm(null); return; } try { - const res = await fetch(`/api/someday-lists?id=${existing.id}`, { + // tasksOnly=true: soft-disconnect — removes tasks but keeps list record with its tab assignment + // so when the user reconnects, the tab is restored automatically without re-dragging + const res = await fetch(`/api/someday-lists?id=${existing.id}&tasksOnly=true`, { method: "DELETE", }); if (res.ok) { + // Remove from local state (clean UI); DB record is kept for tab restoration on reconnect setSomedayLists((prev) => prev.filter((l) => l.id !== existing.id)); setImportStatusMsg({ type: "success", @@ -3683,7 +3686,7 @@ export default function WeeklyView() { }); } } catch (error) { - console.error("Failed to delete list", error); + console.error("Failed to unsync list", error); setImportStatusMsg({ type: "error", text: "Failed to stop syncing list.", @@ -3717,7 +3720,8 @@ export default function WeeklyView() { ); if (!existing) continue; try { - const res = await fetch(`/api/someday-lists?id=${existing.id}`, { + // tasksOnly=true: soft-disconnect — keeps list record with tab for reconnect restoration + const res = await fetch(`/api/someday-lists?id=${existing.id}&tasksOnly=true`, { method: "DELETE", }); if (res.ok) {