Skip to content

feat: persist watchlist and bridge filter/sort preferences across sessions - #25

Merged
Meshmulla merged 1 commit into
stellar-kracken:mainfrom
Mona-i:feat/persist-watchlist-bridge-filter-sort-12
Jul 22, 2026
Merged

feat: persist watchlist and bridge filter/sort preferences across sessions#25
Meshmulla merged 1 commit into
stellar-kracken:mainfrom
Mona-i:feat/persist-watchlist-bridge-filter-sort-12

Conversation

@Mona-i

@Mona-i Mona-i commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Closes #12

Summary

Implements full localStorage persistence for the watchlist and bridge filter/sort state so returning users no longer need to re-apply preferences on every visit.

Changes

src/stores/watchlistStore.ts (new)

  • Zustand persist store for the watchlist, namespaced key swipely:watchlist (v1)
  • normalizeWatchlistState validates/sanitizes persisted shapes; corrupt data falls back to defaults
  • migrate callback handles version upgrades gracefully
  • merge callback migrates the legacy swipely.watchlists.v1 key on first load, then removes it
  • clearActiveWatchlist removes the localStorage key when all lists are empty

src/stores/bridgeFilterSortStore.ts (new)

  • Zustand persist store for bridge statusFilter + sortBy, namespaced key swipely:bridge-filter-sort (v1)
  • normalizeBridgeFilterSortState rejects unknown values and falls back to safe defaults
  • Includes applyBridgeFilterSort helper and getBridgeHealthScore utility

src/hooks/useWatchlist.ts

  • Replaced React-context + raw localStorage implementation with thin facade over useWatchlistStore
  • WatchlistProvider kept as no-op pass-through for call-site compatibility

src/components/BridgeFilterSort.tsx

  • Now reads from / writes to useBridgeFilterSortStore when not controlled by parent props
  • Fully backwards-compatible: controlled prop usage unchanged

src/pages/Bridges.tsx

  • Wires applyBridgeFilterSort into the filteredBridges memo so persisted filter/sort is applied on every render
  • Mounts BridgeFilterSort in the toolbar alongside favorites and refresh controls

src/stores/index.ts

  • Exports both new stores and their helpers

Tests

  • src/stores/watchlistStore.test.ts: rehydration, legacy migration, corrupt-data resilience, clearActiveWatchlist removes persisted state
  • src/stores/bridgeFilterSortStore.test.ts: rehydration, invalid-value guards, corrupt-data resilience, filter/sort utility functions
  • src/hooks/useWatchlist.test.tsx: updated storage-key assertion to the new namespaced key

Acceptance Criteria

  • Watchlist survives reload and browser restart: Zustand persist writes to swipely:watchlist on every mutation
  • Bridge filter/sort selections are restored on return: Zustand persist writes to swipely:bridge-filter-sort on every change
  • Corrupt/outdated persisted data is handled without crashing: normalizeWatchlistState / normalizeBridgeFilterSortState + migrate callbacks
  • Clearing the watchlist clears persisted state: clearActiveWatchlist removes localStorage key when all lists are empty

CI Validation

  • npm run lint: 0 errors
  • npm run type-check: 0 errors
  • npm run test: 56 test files, 603 tests all passing
  • npm run build: production build succeeds

…sions

- Migrate useWatchlist from React context + raw localStorage to a Zustand
  persist store (src/stores/watchlistStore.ts) backed by the namespaced
  key swipely:watchlist (v1). Supports legacy key migration
  (swipely.watchlists.v1), schema normalization, and graceful handling of
  corrupt or outdated persisted data.

- Add src/stores/bridgeFilterSortStore.ts: Zustand persist store for
  bridge status filter and sort-by preferences, namespaced under
  swipely:bridge-filter-sort (v1), with validation guards that fall back
  to safe defaults on unknown/corrupt shapes.

- Update BridgeFilterSort component to read from and write to the
  bridgeFilterSortStore when no controlled props are supplied; controlled
  usage continues to work via the existing prop API.

- Wire applyBridgeFilterSort into Bridges.tsx so the persisted filter/sort
  state is applied to the bridge list on every render.

- Refactor useWatchlist hook to delegate to useWatchlistStore; preserve
  WatchlistProvider as a no-op pass-through for call-site compatibility.

- Export both new stores and their helpers from src/stores/index.ts.

- Add/update unit tests for both stores covering: rehydration across
  restarts, graceful corrupt-data handling, legacy key migration, clear
  clears persisted state, and invalid value guards.
@Meshmulla
Meshmulla merged commit 2456f7c into stellar-kracken:main Jul 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Persist watchlist and bridge filter/sort preferences across sessions

2 participants