fix: prevent planned tasks from being overwritten on login/logout#176
Merged
Conversation
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().
Deploying timetrackerpro with
|
| Latest commit: |
0a129fe
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://aab0101d.timetrackerpro.pages.dev |
| Branch Preview URL: | https://fix-planned-tasks-persistenc.timetrackerpro.pages.dev |
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
migrateFromLocalStorage()overwrote Supabase planned tasks unconditionally — when a user logged out (triggeringmigrateToLocalStorage), 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/todoLoadedRefnever reset on service switch — after login/logout changeddataService, the newloadData()ran with both guard refs stilltrue, allowing mutations to fire against the new service before data finished loading. Fixed by resetting both refs tofalseat the start ofloadData().Root cause trace
migrateToLocalStorage()writes current Supabase planned tasks to localStoragemigrateFromLocalStorage()sees localStorage has tasks, blindly callssavePlannedTasks(localTasks)→ overwrites device B's tasksTest plan
pnpm test run)