Skip to content

fix: prevent planned tasks from being overwritten on login/logout#176

Merged
AdamJ merged 2 commits into
mainfrom
fix/planned-tasks-persistence
Jun 16, 2026
Merged

fix: prevent planned tasks from being overwritten on login/logout#176
AdamJ merged 2 commits into
mainfrom
fix/planned-tasks-persistence

Conversation

@AdamJ

@AdamJ AdamJ commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • migrateFromLocalStorage() overwrote Supabase planned tasks unconditionally — when a user logged out (triggering migrateToLocalStorage), then back in, localStorage's stale snapshot replaced any tasks created on other devices since the logout. Added the same existence guard that categories already had: only migrate from localStorage when Supabase has zero planned tasks.
  • plannedLoadedRef / todoLoadedRef never reset on service switch — after login/logout changed dataService, the new loadData() ran with both guard refs still true, allowing mutations to fire against the new service before data finished loading. Fixed by resetting both refs to false at the start of loadData().

Root cause trace

  1. Logout → migrateToLocalStorage() writes current Supabase planned tasks to localStorage
  2. User adds tasks on another device → stored in Supabase
  3. Login on original device → migrateFromLocalStorage() sees localStorage has tasks, blindly calls savePlannedTasks(localTasks) → overwrites device B's tasks

Test plan

  • Add planned tasks while authenticated, log out, log back in — tasks still present
  • Add planned tasks in guest mode, log in — guest tasks migrate if account has none
  • Add planned tasks on device A, log in on device B — device A tasks not lost
  • Manual sync after login still works correctly
  • All 187 unit tests pass (pnpm test run)

Two bugs caused planned tasks to silently disappear after switching
browsers or logging in and out:

1. migrateFromLocalStorage() unconditionally overwrote Supabase planned
   tasks with localStorage data (no guard like categories had). Since
   migrateToLocalStorage() writes tasks to localStorage on logout, any
   subsequent login would wipe whatever tasks were created on other
   devices since the logout.

   Fixed: only migrate planned tasks from localStorage when Supabase
   has zero planned tasks — matching the existing guard for categories.

2. plannedLoadedRef (and todoLoadedRef) were never reset to false when
   dataService changed (login/logout). The next loadData() call ran
   with the guard already true, allowing mutations to fire against the
   new service before load completed.

   Fixed: reset both guard refs to false at the start of loadData().
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 16, 2026

Copy link
Copy Markdown

Deploying timetrackerpro with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0a129fe
Status: ✅  Deploy successful!
Preview URL: https://aab0101d.timetrackerpro.pages.dev
Branch Preview URL: https://fix-planned-tasks-persistenc.timetrackerpro.pages.dev

View logs

@AdamJ AdamJ added this to Timetraked Jun 16, 2026
@AdamJ AdamJ moved this to In review in Timetraked Jun 16, 2026
@AdamJ AdamJ added bug Something isn't working performance For performance related issues labels Jun 16, 2026
@AdamJ AdamJ linked an issue Jun 16, 2026 that may be closed by this pull request
Two race conditions caused planned tasks to appear missing after auth
state changes:

1. Logout race: the previous code ran migrateToLocalStorage() and
   setDataService(localStorage) in separate effects. React fired
   setDataService synchronously, triggering loadData() before
   migrateToLocalStorage() finished writing. Guest mode loaded empty
   localStorage and showed no tasks.

   Fixed: merged the two effects into one async handler that awaits
   migrateToLocalStorage() before calling setDataService(), ensuring
   loadData() always reads the fully-written snapshot.

2. Login state stale: migrateFromLocalStorage() saved guest tasks to
   Supabase but never updated React state. The current session stayed
   empty until the next page reload.

   Fixed: reload planned tasks from Supabase after migration completes
   and push the result into state so the session reflects what was
   just written.

Also removed previousAuthState useState (replaced by prevAuthRef) since
it was only used for logout detection and the state update was causing
an extra render cycle.
@AdamJ AdamJ merged commit c7fc0c1 into main Jun 16, 2026
3 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in Timetraked Jun 16, 2026
@AdamJ AdamJ deleted the fix/planned-tasks-persistence branch June 16, 2026 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working performance For performance related issues

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Bug - tasks are not synced between states

1 participant