Repository navigation
fix(favorites): keep favorites in sync across devices - #1463
Conversation
Favorites are DB-backed, but the client store persisted `isSynced` to localStorage, so a device that had synced once never revalidated. Changes made on another device (e.g. mobile) never appeared, and add/remove operated against a stale cache (remove silently no-oped; add bounced off a 409). - Stop persisting `isSynced` so every load revalidates (stale-while-revalidate) - Add `useFavoritesSync`: revalidate on mount and on window focus / visibilitychange (throttled) so backgrounded devices pick up remote changes - `removeFavorite` reconciles with the server when the entry is missing from the local cache instead of silently no-oping - `addFavorite` treats a duplicate (409) as success after reconciling - Wire the hook into FavoritesSection, DriveSwitcher, DrivesBrowser - Add store tests for the reconcile paths Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThe PR refactors favorites synchronization across the codebase by introducing a dedicated ChangesFavorites Synchronization Refactor
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e8be3ccac1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Not persisting `isSynced` only stops future writes; users upgrading from a build that persisted it still have `isSynced: true` in localStorage, which Zustand's default merge restores on rehydrate — skipping the load-time revalidation for exactly the stale-cache population this PR targets. Add a custom persist `merge` that always resets `isSynced` to false. Addresses review feedback on useFavorites.ts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Problem
Favorites are database-backed, but the client reads them through a Zustand store that persisted
isSyncedto localStorage. Once a device had synced, it never re-fetched, so:favoritesarray (the DELETE was never sent), and add bounced off a409 "already favorited"(the star rolled back even though it was favorited).Fix
isSynced— every load now revalidates against the database (stale-while-revalidate; the persisted list remains only a fast first-paint cache).isSyncedon rehydrate — not persisting it isn't enough on its own: users upgrading from a build that did persistisSynced: truewould have it merged back by Zustand's default merge, re-skipping the load-time revalidation. A custom persistmergenow forcesisSynced: falseon every rehydrate, covering the legacy-storage upgrade path. (Addresses review feedback.)useFavoritesSynchook — revalidates on mount and on windowfocus/visibilitychange(throttled to 3s), so a backgrounded device (mobile) picks up changes made elsewhere without a manual reload. Wired intoFavoritesSection,DriveSwitcher, andDrivesBrowser, replacing their duplicatedif (!isSynced) fetcheffects.removeFavoritereconciles with the server when the favorite is missing from the local cache (fetch → find real id → delete), instead of silently no-oping.addFavoritetreats a duplicate (409) as success after reconciling with the server, instead of rolling the star back; only rolls back when the server genuinely can't be reached.Files
apps/web/src/hooks/useFavorites.ts— store changes +useFavoritesSynchook + persistmergeapps/web/src/components/layout/left-sidebar/FavoritesSection.tsxapps/web/src/components/layout/navbar/DriveSwitcher.tsxapps/web/src/components/drives/DrivesBrowser.tsxapps/web/src/hooks/__tests__/useFavorites.test.ts— reconcile-path testsValidation
Notes
🤖 Generated with Claude Code