auth-yes/tasks/complete/2026-0827.01.gem.fix.ui.missed-audit-items-0005.md

4.5 KiB

TASK METADATA

  • Target Files:
    • server/routes/events.ts
    • ui/components/sessions/SessionsScript.tsx
    • ui/components/sessions/EventCockpitDeck.tsx
    • ui/components/SessionsPage.tsx
  • Core Objective: Resolve the final 4 untracked discrepancies identified during the Phase 6 UI Audit (DOM desync, missing guest drawer payload, minor typo, and missing sticky action bar).
  • Dependencies: None.
  • Additional Important Notes: This represents the final polish of the Sessions & Events UX before moving on to backend relational decoupling and P2P vouching.

2. Architectural Considerations & Risks

Risks

  1. DOM Ingress Desync: Currently, when an organizer clicks [ 🔄 Rotate ], the backend successfully updates both the pin_code and the slug. However, the frontend JavaScript (rotatePin) only targets and updates the PIN on the UI. The copy buttons for "Link" and "CLI" continue to hold the old slug because their onclick handlers are hardcoded during SSR. Risk: If an organizer rotates the credentials and then clicks "Copy Link", they will mistakenly share the revoked link, leading to confusion and 404s.
  2. Guest Drawer Broken Meta Header: The backend endpoint GET /api/events/:id/attendees only returns { success: true, attendees: [...] }. The client script expects data.event to populate the Max Seats and Expires At countdown. Because data.event is undefined, the header is permanently stuck displaying 0 / 0 Claimed Seats · ⏳ 0h 0m left. Risk: Loss of critical event context while managing guests.
  3. Scroll Fatigue: The [ Delegate Session ] drawer trigger sits at the top of SessionsPage.tsx. As the user accumulates multiple events or sessions, scrolling down the page hides the primary action.

Alternatives

  • For the Sticky Action Bar, we could use CSS position: sticky; top: 0; on the delegation tabs block in SessionsPage.tsx, ensuring the action is always visible without creating a separate floating action button (FAB) which might clutter mobile views.
  • For the UI DOM rotation, we must assign id attributes to the Link and CLI copy pills in EventCockpitDeck.tsx so rotatePin can dynamically overwrite their onclick attributes.

3. Proposed Implementation

Phase 1: Fix Backend Attendees Payload

  1. In server/routes/events.ts, locate GET /api/events/:id/attendees (around line 125).
  2. Currently, the query selects only slug to do the LIKE match. Update this to fetch max_seats and expires_at as well.
  3. Include the event payload in the JSON response: return c.json({ success: true, attendees, event: { max_seats: event.max_seats, expires_at: event.expires_at } }).

Phase 2: Fix DOM Rotation Desync

  1. In ui/components/sessions/EventCockpitDeck.tsx:
    • Locate the Grid and Compact card copy buttons for Link and CLI.
    • Add explicit IDs, for example: id={'link-copy-' + event.id} and id={'cli-copy-' + event.id}.
  2. In ui/components/sessions/SessionsScript.tsx (rotatePin function):
    • Check if data.slug is returned (Jules updated the backend to return pinCode, slug, link, cli).
    • If data.slug is present, locate the link and CLI copy elements and overwrite their onclick handlers dynamically so they copy the fresh credentials.
    • E.g., linkElem.setAttribute('onclick', "copyText(window.location.origin + '/e/" + data.slug + "')");

Phase 3: Section Title Typo

  1. In ui/components/sessions/EventCockpitDeck.tsx (around line 8), change <h2>Event Passes</h2> to <h2>Events</h2>.

Phase 4: Sticky Delegation Action Bar

  1. In ui/components/SessionsPage.tsx, wrap the Delegate Session tab selection block (<div style="display: flex; gap: 0.5rem; margin-bottom: 2rem;">...</div>) in a sticky container.
  2. Example styling: position: sticky; top: 1rem; z-index: 50; background: var(--surface-bg); padding-top: 1rem; margin-top: -1rem; margin-bottom: 2rem;.
  3. Add a slight box-shadow or bottom border on scroll (optional polish) to ensure the tabs float cleanly above scrolling session cards.

Phase 5: Quality Gates

  1. Run deno fmt, deno task lint, and deno task check.
  2. Verify all ui/ui_scripts.test.ts pass and the DOM manipulation syntax is correct.
  3. Author a new test block in server/tests/events.test.ts for GET /api/events/:id/attendees to assert that it successfully returns both the attendees array and the event payload containing max_seats and expires_at.