Skip to content

Repository files navigation

D3 Seasonal Leaderboard

A web app that displays live seasonal leaderboards for Diablo 3, built with Next.js, React, and TypeScript. It authenticates with Blizzard's official game data API via OAuth2, then lets players browse and search rankings by region, season, hardcore mode, party composition, and leaderboard type.

Live Demo

Engineering Highlights

A few decisions in this codebase worth calling out:

  • Secrets never touch the client. Blizzard requires an OAuth2 client-credentials exchange to call the API. That exchange, and the bearer token it produces, live entirely in a 'use server' module (API_requests.js) — the client bundle never sees CLIENT_ID or CLIENT_SECRET.
  • UI options are derived from data, not hardcoded. Rather than shipping a static list of leaderboard types, the app fetches the current season's available leaderboards and computes the "Party" and "Leaderboard" filter options from that response. Add a new leaderboard on Blizzard's side and the UI picks it up automatically — no code change needed.
  • Search is instant because it doesn't hit the network. Once a leaderboard is loaded, typing in the search box filters it in memory on every keystroke instead of re-querying the API, which keeps the interaction fast and avoids hammering a rate-limited third-party API.
  • Components are kept dumb on purpose. Data-fetching and shaping is centralized in page.tsx and API_requests.js; presentational components like RankDisplay and PlayerDetail just render props. That separation keeps the UI layer easy to test and reason about independent of the API's data shape.
  • Typed end-to-end. TypeScript interfaces model Blizzard's actual (fairly irregular) API response shape, and a generic Dropdown<T> component keeps every filter's state type-safe rather than passing strings around everywhere.

How It Works

Blizzard's Diablo 3 API is a read-only data feed with no rendering of its own — this app is the presentation layer on top of it, handling authentication, data shaping, and an interactive UI.

  1. Server-side OAuth2 authentication. src/modules/API_requests.js exchanges CLIENT_ID/CLIENT_SECRET for a bearer token via the client-credentials grant on first use, caches it in memory, and reuses it for subsequent calls.

  2. Three chained API calls drive the UI. The root page (src/app/page.tsx) fetches data in a dependency chain, each step unlocking the next set of filter options:

    • GetSeasonIndex(region) — resolves the current season number for the selected region.
    • GetSeasonLeaderboardTypes(region, season) — lists every leaderboard available for that season (solo classes, team sizes, hardcore variants, etc.), parsed client-side to build the "Party" and "Leaderboard" dropdown options dynamically.
    • GetSeasonalLeaderboard(region, season, leaderboard) — fetches the ranked rows of players/teams for the chosen combination of filters.
  3. Client-side filtering and search. Region, season, hardcore, party, and leaderboard type are all React state, so changing any filter re-triggers the relevant fetch via useEffect. The search box filters the already-loaded rows in memory against player name, clan, and class.

  4. Presentational rendering. RankDisplay renders one leaderboard row — hero portraits, rank styling by placement, and greater-rift clear time with a red-to-green color gradient based on speed — while PlayerDetail renders one player's stat line.

Tech Stack

Layer Choice
Framework Next.js 15 (App Router, Turbopack)
UI React 19
Language TypeScript
Styling Tailwind CSS 4
Data source Blizzard Battle.net API (Diablo 3 game data, OAuth2 client-credentials flow)
Linting ESLint (eslint-config-next)

Getting Started

You'll need a Battle.net API client:

  1. Create an account and a client at develop.battle.net/access/clients.
  2. Create a .env file in the project root with your Client ID and Client Secret:
CLIENT_ID=your_client_id
CLIENT_SECRET=your_client_secret

Then:

npm install
npm run dev

Open http://localhost:3000 to view it.

Scripts

  • npm run dev — start the dev server (Turbopack)
  • npm run build — production build
  • npm run start — serve the production build
  • npm run lint — run ESLint

Project Structure

src/
  app/
    page.tsx        # Root route — owns filter state and orchestrates the 3-step data fetch
    layout.tsx       # Root layout, global styles
  components/
    Dropdown.tsx      # Generic typed <select> wrapper used for all filters
    RankDisplay.tsx    # Renders one leaderboard row: portraits, rank badge, stat columns
    PlayerDetail.tsx   # Renders one player's name/clan/class/level/paragon line
    NavBar.tsx / NavButton.tsx / Background.tsx / ScrollingFrame.tsx / Shadows.tsx  # Layout & chrome
  modules/
    API_requests.js   # Server-only Blizzard API client (OAuth2 token fetch + caching, 3 leaderboard endpoints)
    RiftTime.js        # Converts raw greater-rift clear time to minutes and maps it to a color gradient
    stringFuncs.js      # Small string-formatting helpers (title-casing labels)

About

A web app that displays live seasonal leaderboards for Diablo 3, built with Next.js, React, and TypeScript. It authenticates with Blizzard's official game data API via OAuth2, then lets players browse and search rankings by region, season, hardcore mode, party composition, and leaderboard type.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages