Persist dashboard periods and explore genre filters in URL via nuqs

- Add `nuqs` dependency; define `dashboardSearchParams` and
  `exploreSearchParams` loaders in new `search-params.ts` files
- Thread `moviePeriod`/`episodePeriod` from URL into `StatsSection`
  and `StatsDisplay`, replacing local `useState` with `useQueryStates`
- Rename `getUserStats` fields `moviesThisMonth`/`episodesThisWeek` →
  `movieCount`/`episodeCount` and accept period args so SSR stats
  match the active URL params
- Pre-fetch genre-filtered results server-side on the explore page
  when `movieGenre`/`tvGenre` params are present; pass as
  `initialGenreItems` to `FilterableTitleRow` so first paint is
  already populated
- Render genre chips as `<Link>` elements (with click-handler
  fallback) so genre selections produce shareable, bookmarkable URLs
This commit is contained in:
2026-03-08 14:32:09 -04:00
parent 0838e5fb74
commit 2bb5af042b
12 changed files with 213 additions and 70 deletions
+11 -7
View File
@@ -144,15 +144,19 @@ export function getWatchHistory(
}
export interface DashboardStats {
moviesThisMonth: number;
episodesThisWeek: number;
movieCount: number;
episodeCount: number;
librarySize: number;
completed: number;
}
export function getUserStats(userId: string): DashboardStats {
const moviesThisMonth = getWatchCount(userId, "movies", "this_month");
const episodesThisWeek = getWatchCount(userId, "episodes", "this_week");
export function getUserStats(
userId: string,
moviePeriod: TimePeriod = "this_month",
episodePeriod: TimePeriod = "this_week",
): DashboardStats {
const movieCount = getWatchCount(userId, "movies", moviePeriod);
const episodeCount = getWatchCount(userId, "episodes", episodePeriod);
const [statusCounts] = db
.select({
@@ -164,8 +168,8 @@ export function getUserStats(userId: string): DashboardStats {
.all();
return {
moviesThisMonth,
episodesThisWeek,
movieCount,
episodeCount,
librarySize: statusCounts?.librarySize ?? 0,
completed: statusCounts?.completed ?? 0,
};