docs: pagination and day grouping design spec
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user