Skip to content

Latest commit

 

History

History
236 lines (182 loc) · 6.5 KB

File metadata and controls

236 lines (182 loc) · 6.5 KB

Filter State Persistence Implementation

Overview

This implementation adds URL-based filter state persistence for the Projects and Earnings pages, enabling shareable URLs, browser navigation support, and state restoration on page reload.

Implementation Summary

1. Core Hook: useFilterQueryState

Location: hooks/useFilterQueryState.ts

A reusable custom hook that manages filter state in URL query parameters.

Features:

  • Single source of truth (URL is the state)
  • Type-safe with TypeScript generics
  • Automatic serialization/deserialization
  • Clean URLs (removes params that match defaults)
  • Client-side navigation (no page reload)

Usage Example:

const { filters, updateFilters, resetFilters } = useFilterQueryState({
  style: "All Styles",
  virality: ["high", "medium", "low"],
  vault: "pending"
});

2. Projects Page Implementation

Location: app/projects/page.tsx

Filters Persisted:

  • style - Caption style (string)
  • virality - Virality levels (array of strings)
  • vault - Vault status (string)

URL Examples:

/projects?style=Minimalist&virality=high,medium&vault=listed
/projects?style=Bold+%26+Dynamic&vault=history
/projects (default state)

Changes Made:

  • Replaced local useState with useFilterQueryState
  • Updated filter callbacks to use updateFilters
  • Maintained all existing UI functionality
  • No breaking changes to child components

3. Earnings Page Implementation

Location: app/earnings/page.tsx Component: components/dashboard/EarningsTable.tsx

Filters Persisted:

  • search - Search term (string)
  • startDate - Start date for filtering (string, ISO format)
  • endDate - End date for filtering (string, ISO format)

URL Examples:

/earnings?search=tiktok&startDate=2026-01-01&endDate=2026-01-31
/earnings?search=completed
/earnings (default state)

Changes Made:

  • Removed EarningsSearchContext dependency (no longer needed)
  • Updated EarningsTable to accept filter props
  • Added date range filtering support
  • Maintained debounced search behavior

Features Implemented

✅ URL Query Parameter Sync

  • Filters automatically sync to URL
  • Client-side navigation (no page reload)
  • Clean URLs (default values omitted)

✅ State → URL Sync

  • Filter changes immediately update URL
  • Multiple filters can be updated simultaneously
  • Array values serialized as comma-separated strings

✅ URL → State Initialization

  • Page load reads query params
  • Invalid params fallback to defaults
  • Type-safe parsing (strings, arrays, numbers, booleans)

✅ Navigation Behavior

  • Browser Back/Forward buttons work correctly
  • Filter state preserved in history
  • No state reset on component remount

✅ Shareable URLs

  • Copy URL to share exact filtered view
  • Another user sees identical filters
  • Works across sessions and devices

✅ Edge Case Handling

  • Missing params → use defaults
  • Invalid params → fallback safely
  • Empty arrays → remove param
  • Special characters → properly encoded

Testing

Test Files Created

  1. __tests__/hooks/useFilterQueryState.test.tsx - Hook unit tests
  2. __tests__/projects/projects-filters.test.tsx - Projects page integration tests
  3. __tests__/earnings/earnings-filters.test.tsx - Earnings page integration tests

Test Coverage

  • ✅ URL initialization with/without params
  • ✅ State updates URL correctly
  • ✅ Back navigation restores filters
  • ✅ Shareable state works
  • ✅ Edge cases (missing, invalid params)
  • ✅ No page reload on filter changes

Running Tests

# Install dependencies first (requires disk space)
npm install --save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event jest jest-environment-jsdom @types/jest

# Run tests
npm test

# Watch mode
npm run test:watch

# Coverage report
npm run test:coverage

Configuration Files

jest.config.js

Jest configuration for Next.js with TypeScript support.

jest.setup.js

Test environment setup with Next.js router mocks.

Code Quality

Single Source of Truth

  • URL is the only source of filter state
  • No duplicate state in components
  • Eliminates sync issues

Clean Components

  • Filter logic centralized in hook
  • Components remain focused on UI
  • Easy to test and maintain

Type Safety

  • Full TypeScript support
  • Generic hook works with any filter shape
  • Compile-time validation

Performance

  • Debounced search (300ms)
  • Memoized filtering logic
  • Efficient URL updates

Migration Notes

Breaking Changes

None. All existing functionality preserved.

Removed Dependencies

  • EarningsSearchContext (replaced by URL state)

Added Dependencies

  • None (uses built-in Next.js hooks)

Browser Compatibility

Works with all modern browsers that support:

  • URLSearchParams API
  • Next.js App Router
  • History API

Future Enhancements

Potential improvements:

  1. Add date picker UI for earnings date range
  2. Persist filter preferences to localStorage
  3. Add "Save Filter Preset" feature
  4. Analytics tracking for popular filters
  5. URL shortening for complex filter combinations

Commit Message

feat(filters): persist filter state in URL for projects and earnings

- Sync filter state with query parameters
- Initialize UI from URL on page load
- Support back/forward navigation state
- Enable shareable filtered URLs
- Add comprehensive test coverage
- Maintain backward compatibility

Closes #[ISSUE_NUMBER]

Manual Testing Checklist

Projects Page

  • Apply filters → refresh → verify persistence
  • Change style filter → check URL updates
  • Toggle virality levels → check URL updates
  • Change vault status → check URL updates
  • Navigate away and back → filters restored
  • Share URL with colleague → same view loads
  • Browser back/forward → filters change correctly
  • Reset filters → URL clears

Earnings Page

  • Type in search → check URL updates (debounced)
  • Clear search → URL param removed
  • Navigate away and back → search restored
  • Share URL with search term → same results
  • Browser back/forward → search changes correctly
  • Refresh page → search persists

Edge Cases

  • Load URL with invalid params → graceful fallback
  • Load URL with missing params → defaults used
  • Special characters in search → properly encoded
  • Empty filter values → params removed
  • Multiple rapid filter changes → no race conditions

Support

For questions or issues, contact the development team or create an issue in the repository.