Skip to content

feat(leaderboard): season-driven data loading with URL synchronization#583

Open
petahade wants to merge 3 commits into
Arenax-gaming:mainfrom
petahade:feat/leaderboard-season-url-sync
Open

feat(leaderboard): season-driven data loading with URL synchronization#583
petahade wants to merge 3 commits into
Arenax-gaming:mainfrom
petahade:feat/leaderboard-season-url-sync

Conversation

@petahade

@petahade petahade commented Jun 24, 2026

Copy link
Copy Markdown

Closes #554


Summary

This PR completes the leaderboard season flow so that selecting a season actually changes what data is fetched — rather than only toggling local UI state — and keeps the browser URL in sync with the active selection.

Problem

SeasonSelector previously called a local setSeason that had no effect on data fetching. useLeaderboard never received or forwarded the season, so every API call always returned the same season-agnostic results regardless of what the user selected. The URL was also never updated, so refreshing the page or sharing a link always reset the view to the default season.

Changes

frontend/src/hooks/useLeaderboard.ts

  • Added optional season?: string as a fourth parameter.
  • season is included in the React Query queryKey — a season change produces a new cache entry and a fresh fetch, while re-selecting the same season is a no-op (no duplicate request).
  • Uses URLSearchParams to append ?season=<id> to every API call when a season is provided. When omitted, the query string is unchanged (backwards-compatible with existing callers).

frontend/src/app/leaderboard/page.tsx

  • Added a SEASONS constant (matching SeasonSelector's list) and a new Season <Select> filter in the Filters card — filter grid expanded from 3 to 4 columns (lg:grid-cols-4).
  • Season state is initialised from ?season= on page load via useSearchParams(), falling back to "current".
  • handleSeasonChange updates local state, resets pagination to page 1, and pushes the updated query string with router.push(..., { scroll: false }) — no full reload, native browser back/forward preserved. Selecting "current" removes the param to keep URLs clean.
  • useLeaderboard now receives season and returns isFetching in addition to isLoading.
  • Table body switches skeleton rows on isFetching (not just isLoading) so stale data is replaced immediately when a season-specific request starts, even when a stale cache entry exists.
  • A Loader2 spinner appears next to the "Rankings" heading when isFetching && !isLoading (background refetch in progress).
  • Pagination visibility and its isLoading prop are also gated on isFetching.
  • Wrapped in <Suspense> as required by Next.js 14 for useSearchParams in client components.

frontend/src/app/leaderboards/page.tsx

  • Replaced onChange={setSeason} on SeasonSelector with onChange={handleSeasonChange}, which uses the same URL-sync logic described above.
  • Season state initialised from ?season= query param on page load.
  • useLeaderboard now receives season so API requests include the correct season parameter.
  • isFetching drives the LeaderboardTable isLoading prop and a Loader2 spinner in the table heading, showing feedback during season switches.
  • Wrapped in <Suspense> for the same useSearchParams requirement.

Behaviour

Scenario Before After
User selects Season 3 Dropdown changes, data unchanged API called with ?season=season-3, new rankings rendered
Season change in progress Old rankings remain with no indicator Skeleton rows + spinner shown until response arrives
Page load with ?season=season-2 in URL Season dropdown ignored param, showed default Dropdown pre-selected to Season 2, correct data fetched
Duplicate season selection N/A React Query cache hit — no network request
Sharing a URL with ?season=season-4 Recipient sees default season Recipient sees Season 4 rankings
Browser back after season change N/A Previous season restored from URL history
Selecting "Current Season" N/A ?season= param removed, URL stays clean

Test plan

  • Open /leaderboard — default season ("Current Season") is selected, no ?season= in URL.
  • Switch to Season 3 — URL updates to ?season=season-3 without a full page reload; skeleton rows appear briefly; results refresh.
  • Switch back to Current Season — ?season= param is removed from URL.
  • Hard-refresh at ?season=season-2 — Season 2 is pre-selected and the correct data loads.
  • Use browser back/forward after changing seasons — URL and selection stay in sync.
  • Change category while a non-default season is active — ?season= param is preserved in URL.
  • Repeat all steps on /leaderboards with the SeasonSelector dropdown.
  • Confirm existing callers of useLeaderboard without a season argument are unaffected (no ?season= appended, same query key behaviour as before).

petahade added 3 commits June 24, 2026 16:36
- Extend `useLeaderboard` with an optional `season` param; appends
  `?season=<id>` to every API request and includes it in the React Query
  key so season changes trigger fresh fetches rather than reusing cached
  data for the wrong season.

- `/leaderboard` page: add a Season filter (alongside category/search/sort),
  initialize it from the `?season=` query param on page load, and update
  the URL via `router.push(..., { scroll: false })` on each change — no
  full reload, back/forward navigation preserved.

- `/leaderboards` page: wire existing `SeasonSelector` to the same URL-sync
  handler instead of isolated local state; season is now passed through to
  `useLeaderboard` so the API call reflects the selection.

- Both pages use `isFetching` (not just `isLoading`) to show skeleton rows
  and a `Loader2` spinner in the table heading while a season-specific
  request is in flight, preventing stale rankings from lingering on screen.

- Wrap both page components in a `<Suspense>` boundary required by Next.js
  14 for `useSearchParams` in client components.
@petahade petahade requested a review from anonfedora as a code owner June 24, 2026 19:23
@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown

@petahade is attempting to deploy a commit to the paul joseph's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Jun 24, 2026

Copy link
Copy Markdown

@petahade Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

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.

[frontend] - Season selector in leaderboard does not fetch season-specific data

1 participant