Files
jackboxpartypack-gamepicker/docs/superpowers/specs/2026-03-23-pagination-day-grouping-design.md
2026-03-23 11:16:33 -04:00

4.1 KiB

Pagination & Day Grouping — Design Spec

Date: 2026-03-23 Status: Approved

Overview

Two enhancements to the session History page:

  1. Pagination — When "Show X" is set to a value other than "All", add Prev/Next navigation to access older sessions.
  2. Day Grouping — Group sessions that occurred on the same calendar day under a shared header bar.

Backend Changes

GET /api/sessions — New offset parameter

Add an offset query parameter (default 0) to the existing endpoint. Works with the existing limit, filter, X-Total-Count, and X-Absolute-Total headers.

GET /api/sessions?filter=default&limit=5&offset=10

New response header:

  • X-Prev-Last-Date — When offset > 0, the created_at timestamp of the session immediately before the current page (the session at position offset - 1). Used by the frontend to detect whether the first day group on the current page is a continuation from the previous page. Omitted when offset is 0.

SQL changes: Add OFFSET clause to the existing query. For X-Prev-Last-Date, run a small secondary query to fetch the created_at of the session at position offset - 1 (same filter/ordering).

No other backend changes required.

Frontend Changes

State

  • page (number, default 1) — current page number. Derived from offset: offset = (page - 1) * limit. Not persisted in localStorage; resets to 1 on navigation.
  • prevLastDate (string|null) — from X-Prev-Last-Date header. Used for "(continued)" detection.

Page math

totalPages = Math.ceil(totalCount / limitNum)
offset = (page - 1) * limitNum

When limit is "all", pagination is disabled (no offset, no pagination bar).

loadSessions changes

Pass offset as a query parameter alongside filter and limit. Read X-Prev-Last-Date from response headers.

Page reset triggers

Changing filter, limit, or entering/exiting selectMode resets page to 1.

Day Grouping (render-time only)

Group the flat session array by local calendar date at render time. For each group:

  1. Day header bar — Styled with bg-[#1e2a3a] (dark) / bg-gray-100 (light), left border accent (border-l-3 border-indigo-500), contains:
    • Full date: "Sunday, Mar 23, 2026"
    • Right side: session count ("2 sessions") and, if Sunday, "🎲 Game Night"
  2. Session cards — Indented slightly (ml-3) beneath their day header. Display time only (e.g., "7:30 PM") since the full date is in the header. Remove the per-card "· Sunday" text and per-card "🎲 Game Night" badge since that information is now on the day header.

"(continued)" detection

When page > 1 and prevLastDate is set:

  • Parse the previous page's last session date to a local calendar date string
  • If it matches the first day group's date, append an italic "(continued)" tag to that day header (no session count shown for continued groups since the count would be incomplete)

Pagination bar

Rendered below the session list, above the multi-select action bar (if active). Only shown when limit !== "all" and totalPages > 1.

Layout: ← Prev button | "Page X of Y" text | Next → button

  • Prev button disabled (grayed out) on page 1
  • Next button disabled on last page
  • Active buttons use indigo (bg-indigo-600)
  • Disabled buttons use gray (bg-gray-600/700 with cursor-not-allowed)

Multi-select interaction

Day header bars are not selectable. Only session cards participate in multi-select. Checkboxes render inside the indented card area as they do today. Changing pages clears selected IDs but keeps select mode active.

"Visible" count update

The existing "X visible (Y total)" label continues to work as-is. sessions.length reflects the current page's sessions.

Scope

  • No changes to SessionDetail.jsx
  • No changes to bulk endpoints
  • No new dependencies
  • The dateUtils.js gains a formatDayHeader helper (e.g., "Sunday, Mar 23, 2026") and a getLocalDateKey helper for grouping
  • Existing tests for GET /sessions updated to cover offset parameter; new tests for X-Prev-Last-Date header