auth-yes/tasks/complete/2026-0826.05.gem.feat.sessions-ui.sessions-and-guest-drawer-overhaul-2023.ph5.md
google-labs-jules[bot] d86642ce31 feat: Sessions UI overhaul and backend revocation fix
- Update `DELETE /api/sessions/:id` in `server/routes/sessions.ts` to allow event creators to delete guests' sessions.
- Update page hierarchy and top headings in `ui/components/SessionsPage.tsx`.
- Refactor `EventAttendeesDrawer.tsx` to `EventGuestsDrawer.tsx` as a fixed slide-over overlay.
- Add multi-event compact view toggle with `localStorage` persistence in `EventCockpitDeck.tsx`.
- Standardize dynamic countdown pills across `EventCockpitDeck.tsx`, `EventGuestsDrawer.tsx`, `SessionDeck.tsx`, and `SessionTable.tsx`.
- Optimize mobile session deck in `SessionDeck.tsx`.

Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
2026-08-27 04:06:19 +00:00

156 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TASK METADATA
- **Target Files:** `server/routes/sessions.ts`, `server/routes/events.ts`,
`ui/components/SessionsPage.tsx`,
`ui/components/sessions/EventCockpitDeck.tsx`,
`ui/components/sessions/EventAttendeesDrawer.tsx` (refactored/renamed to
`EventGuestsDrawer.tsx`), `ui/components/sessions/SessionDeck.tsx`,
`ui/components/sessions/SessionTable.tsx`,
`ui/components/sessions/SessionsScript.tsx`, `server/tests/events.test.ts`,
`server/tests/scopes.test.ts`, `ui/ui_scripts.test.ts`
- **Core Objective:** Implement Phase 5 Overhaul: Fix backend attendee session
revocation permission checks, build a true fixed slide-over Guest Drawer,
standardize dynamic countdown pills, add multi-event compact density toggle,
and clean up page/session visual hierarchy.
- **Dependencies:** None.
- **Additional Important Notes:** Must remain 100% pure React-free Hono SSR JSX.
All client interactions in `SessionsScript.tsx` must use native vanilla
JavaScript DOM APIs.
---
## 2. Architectural Considerations & Risks
- **Risks:**
- **Zero-Trust Revocation Leakage:** When allowing event creators to
delete/revoke attendee sessions via `DELETE /api/sessions/:id`, ensure the
query strictly verifies that the session belongs to a guest user claimed
under an event pass created by `auth.userId` (or that caller is global
admin). Never allow arbitrary session deletions across different event
creators.
- **DOM Stacking & Focus Trapping:** A fixed slide-over drawer must properly
layer (`z-index: 1050`) over the background page and support backdrop
dismissal and `Escape` key capture without disrupting background table
states.
- **Mobile Density Regressions:** Ensure the mobile slide-up bottom sheet does
not block necessary viewport scrolling or clip action buttons on small
mobile viewports (320px375px).
- **Alternatives:**
- _In-Page Expandable Row vs. Fixed Slide-Over Panel:_ In-page expandable
cards cause massive vertical jumping and layout disruption when 510 events
are active. A dedicated fixed slide-over drawer (right panel on desktop,
bottom sheet on mobile) provides isolated context, independent scrolling,
and a pinned summary header without disturbing the background dashboard.
---
## 3. Proposed Implementation
### Phase 1: Backend Revocation Permission Fix (`server/routes/sessions.ts`)
1. **Authorize Event Creators in `DELETE /api/sessions/:id`:**
- Update `DELETE /api/sessions/:id` to check whether the target session is
owned by `auth.userId`, or if caller is `isGlobalAdmin`, OR if the session
belongs to a guest user of an event pass created by `auth.userId`:
```sql
SELECT s.id
FROM sessions s
JOIN users u ON s.user_id = u.id
WHERE s.id = ${targetSessionId}
AND (
s.user_id = ${auth.userId}
OR ${isAdmin}
OR EXISTS (
SELECT 1 FROM event_passes ep
WHERE ep.created_by = ${auth.userId}
AND u.username LIKE 'guest_' || ep.slug || '_%'
)
)
```
- If found, delete the session from Valkey cache (`valkey.del`) and
PostgreSQL (`DELETE FROM sessions WHERE id = ${targetSessionId}`), logging
the audit event.
- Return `{ success: true }`.
### Phase 2: Page Hierarchy & Section Titles (`ui/components/SessionsPage.tsx`)
1. **Page Title:**
- Update top `<h1>` in `SessionsPage.tsx` from `Active Sessions & Passes` to
**`Sessions & Passes`**.
2. **Missing Section Headings:**
- Section 1: `<h2>Event Passes</h2>` (with compact density toggle).
- Section 2: Add a prominent `<h2>Sessions</h2>` heading directly above
`SessionTable` and `SessionDeck` with subtitle _"Direct device logins,
passkey authentications, and delegated agent tokens."_
### Phase 3: True Fixed Slide-Over Panel (`EventGuestsDrawer.tsx` & `SessionsScript.tsx`)
1. **Drawer Component Overhaul
(`ui/components/sessions/EventAttendeesDrawer.tsx` ->
`EventGuestsDrawer.tsx`):**
- Refactor the component from an in-line `<div class="card">` into a fixed
slide-over overlay:
- **Desktop:**
`position: fixed; top: 0; right: 0; width: 420px; height: 100vh; background: var(--surface-card); box-shadow: var(--shadow-lg); z-index: 1050; display: flex; flex-direction: column;`
- **Mobile:** Full-width slide-up bottom sheet
(`width: 100vw; height: 80vh; bottom: 0; right: 0; border-radius: 16px 16px 0 0;`).
- **Backdrop:** Dimmed backdrop overlay
(`position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 1040;`)
closing on click.
2. **Pinned Contextual Header:**
- **Title:**
`<h2 id="guestDrawerTitle" style="margin: 0; font-size: 1.25rem;">[Event Name] Guests</h2>`
- **Subheader Context Bar:**
`<div id="guestDrawerContext" style="font-size: 0.8rem; color: var(--text-secondary); margin-top: 0.25rem;">Event Pass · [N] / [Max] Claimed Seats · ⏳ [Xh Ym left] · (Expires [Time])</div>`
- **Close Button:** Accessible close button in top right.
3. **Streamlined Roster Rows (`SessionsScript.tsx`):**
- Discard repeated static expiration timestamps from individual rows.
- Render clean, distinct cards for each guest seat:
- **Left:** `Seat #[N]` (`guest_<slug>_<N>`) + relative join timestamp
(`Joined 5m ago`).
- **Status Badge:** `🟢 Active` / `⏸️ Paused`.
- **Right Actions:** Compact `[ ⏸️ Pause ]` / `[ ▶️ Resume ]` toggle and
`[ 🗑️ Revoke ]` trigger.
4. **Standardize Terminology:**
- Use **`Event Guests`** and **`Claimed Seats`** across all drawer titles,
buttons (`[ 👥 Manage Guests (N) ]`), and notices.
### Phase 4: Dynamic Countdown Standardization & Density Polish (`EventCockpitDeck.tsx`, `SessionDeck.tsx`, `SessionTable.tsx`)
1. **Standardized Countdown Pill:**
- Create a reusable countdown formatter rendering:
`⏳ 2h 45m left · (Expires 10:39 PM)` (or
`⏳ 29d left · (Expires Sep 25)`).
- Dynamic status coloring: **Green** (healthy) -> **Amber** (<1h remaining)
-> **Red** (expired).
- Apply consistently across Event Pass Cards and the Sessions Table/Deck.
2. **Multi-Event Compact Density Toggle (`EventCockpitDeck.tsx`):**
- Add a `[ 🗂️ Grid ]` / `[ 📋 Compact ]` density toggle at the top of the
`Event Passes` section.
- In **Compact Mode**, collapse each event card into a sleek 1-row summary
strip
(`Title · 🟢 Active · ⏳ 2h 45m left · 12/50 Seats · PIN: 749-123 · [ 👥 Guests (12) ] · [ ▸ Details ]`),
fitting 10+ active events in a single screen.
3. **Mobile Session Card Optimization (`SessionDeck.tsx`):**
- Remove the dedicated full-width bottom row on remote session cards.
- Move `[ 🗑️ Revoke ]` inline into the top card header row next to the status
badge as a compact button (`btn-outline-danger`), reducing card height by
50% and fitting 45 more sessions per screen.
### Phase 5: Quality Gates & Testing
1. **Unit Tests (`server/tests/events.test.ts` & `scopes.test.ts`):**
- Test event host revoking a guest attendee session via
`DELETE /api/sessions/:id` succeeds (200 OK).
- Test non-owner unauthorized user attempting to revoke an attendee session
is rejected (404/403).
- Test guest list API returns active claimed seats.
2. **Hermetic UI Validation (`ui/ui_scripts.test.ts`):**
- Verify all vanilla JavaScript drawer controllers, density toggles, and
countdown scripts in `SessionsScript.tsx` parse and evaluate cleanly with
zero syntax errors.
3. **Formatting & Linting:**
- Ensure `deno fmt`, `deno task lint`, `deno task check`, and
`deno test --allow-all` execute with 100% green status.