auth-yes/tasks/new/2026-0827.06.gem.feat.ui.sessions-docking-and-creation-flow-1130.md

166 lines
7.3 KiB
Markdown

# TASK METADATA
- **Target Files:**
- `ui/components/SessionsPage.tsx`
- `ui/components/sessions/DirectPassDrawer.tsx`
- `ui/components/sessions/WorkshopDrawer.tsx`
- `ui/components/sessions/SessionsScript.tsx`
- `ui/ui_scripts.test.ts`
- **Core Objective:** Resolve Round 4 UI defects by docking the sticky
sub-header beneath the main app top bar, standardizing single session creation
to full parity with workshop passes, eliminating `<summary>` double arrows
while preserving `(Optional)` labels, and implementing a rapid creation flow
(`[ Create Another ]` + `[ OK ]`) with tab-locking during handoff states.
- **Dependencies:** None.
- **Additional Important Notes:** Must remain 100% pure React-free Hono SSR JSX.
All state transitions in `SessionsScript.tsx` must use native vanilla
JavaScript DOM APIs.
---
## 2. Architectural Considerations & Risks
### Risks
1. **Navbar Collision on Mobile Viewports:** On narrow screens, the top app bar
height might vary depending on wrapped elements.
- _Mitigation:_ Use `top: var(--top-bar-height, 57px); z-index: 30;` with a
solid background (`var(--surface-bg)`) to prevent cards from scrolling
through transparent gaps or overlapping the fixed `.top-bar` (which sits at
`z-index: 40`).
2. **State Leakage Across Tabs:** If a user mints a Workshop Pass, the handoff
screen appears. If they click the "Single Pass" tab while the event handoff
is still visible, the form displays a dirty or stale state.
- _Mitigation:_ Lock the tab switcher (`pointer-events: none; opacity: 0.5;`
or visually disable the buttons) while in either `handoffModal` or
`eventHandoffState`. Tab navigation is automatically re-enabled when the
user clicks `[ Create Another ]` or closes the drawer.
3. **Double Arrow Rendering:** Native `<details><summary>` elements
automatically render disclosure triangles in modern browsers.
- _Mitigation:_ Purge all explicit `▸` characters from `<summary>` text
strings across both drawer templates.
### Alternatives
- **Closing the Drawer Immediately on Creation:** We considered closing the
drawer right after minting and letting the user copy links from the main page
deck. However, showing the 1-click link, PIN, and CLI export immediately upon
creation in a dedicated handoff card provides essential visual confirmation
and zero-friction copying before returning to the dashboard.
---
## 3. Proposed Implementation
### Phase 1: Viewport Docking (`ui/components/SessionsPage.tsx`)
1. Locate the `Sessions & Events` sub-header block in `SessionsPage.tsx`.
2. Update the sticky styling from `top: 0; z-index: 40;` to:
```css
position: sticky;
top: var(--top-bar-height, 57px);
z-index: 30;
background: var(--surface-bg, #0f172a);
padding: 0.75rem 0;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--border-subtle);
```
### Phase 2: Single Pass Drawer Parity & Form Hiding (`ui/components/sessions/DirectPassDrawer.tsx`)
1. Wrap the Single Pass creation form in
`<div id="delegateCreateState" style="display: block;">`.
2. Update the submit button:
- Label: **`[ Create Session ]`** (replace `"Mint & Delegate Session"`).
- Standardize styling to match `btn-primary`.
3. In the Accordion `<summary>`:
- Remove the `` character.
- Label as: **`"Customize App Permissions & Scopes (Optional)"`**.
4. In `#handoffModal`:
- Change the 1-Click Link copy button from `btn-primary` to uniform
`btn-outline`.
- Update footer actions:
- Replace the single `"Done (Session is Active)"` button with a dual-action
flex container:
- **`[ Create Another ]`**
(`type="button" class="btn-outline" onclick="createAnotherSession()"`)
- **`[ OK ]`**
(`type="button" class="btn-primary" onclick="closeDelegateDrawer()"`)
### Phase 3: Workshop Drawer Parity & Accordion Cleanliness (`ui/components/sessions/WorkshopDrawer.tsx`)
1. Update the submit button:
- Label: **`[ Create Event ]`** (replace `"🎟️ Launch Workshop Pass"`).
2. In the Custom Vanity Slug & PIN `<summary>`:
- Remove the `` character.
- Label as: **`"Custom Vanity Slug & PIN Code (Optional)"`**.
3. In `#eventHandoffState`:
- Update footer actions to match Single Pass:
- **`[ Create Another ]`**
(`type="button" class="btn-outline" onclick="createAnotherEvent()"`)
- **`[ OK ]`**
(`type="button" class="btn-primary" onclick="closeDelegateDrawer()"`)
### Phase 4: Client State Machine & Tab Locking (`ui/components/sessions/SessionsScript.tsx`)
1. **Single Session Submit Handler (`handleDelegateSession`):**
- On success, set `#delegateCreateState.style.display = 'none'` and
`#handoffModal.style.display = 'block'`.
- Call `lockDelegationTabs(true)` to prevent switching tabs while viewing the
handoff token.
2. **Event Creation Submit Handler (`handleCreateEvent`):**
- On success, set `#eventCreateState.style.display = 'none'` and
`#eventHandoffState.style.display = 'block'`.
- Call `lockDelegationTabs(true)`.
3. **Tab Locking Helpers:**
- `lockDelegationTabs(locked)`: Toggles `disabled` state and
`opacity: 0.5; pointer-events: none;` on `#tabBtnDirectPass` and
`#tabBtnWorkshopPass`.
4. **"Create Another" Handlers:**
- `createAnotherSession()`:
- Reset `#delegateForm` input values (default back to 1 Hour and
Read-Only).
- `#handoffModal.style.display = 'none'`.
- `#delegateCreateState.style.display = 'block'`.
- `lockDelegationTabs(false)`.
- Focus `#delegateLabel`.
- `createAnotherEvent()`:
- Reset `#eventForm` input values (default back to 50 seats and 3 hours).
- `#eventHandoffState.style.display = 'none'`.
- `#eventCreateState.style.display = 'block'`.
- `lockDelegationTabs(false)`.
- Focus `#eventName`.
5. **Drawer Open/Close Reset:**
- When calling `openDelegateDrawer()`, ensure `lockDelegationTabs(false)` is
invoked and both form states are reset to visible State 1.
### Phase 5: Expired Events Accordion & 1-Click Reopen (`ui/components/sessions/EventCockpitDeck.tsx`)
1. **Active vs. Expired Separation:**
- Filter `eventPasses` into `activeEvents` and `expiredEvents`
(`expires_at <= NOW()` or `is_active = FALSE`).
2. **Collapsible Accordion:**
- Below the active deck, render a native `<details>` block:
```html
<details
style="margin-top: 1.5rem; background: var(--surface-card); border: 1px solid var(--border-subtle); border-radius: var(--radius-md); padding: 0.75rem 1rem;">
<summary style="font-weight: 600; font-size: 0.95rem; cursor: pointer; color: var(--text-secondary);">
📁 Expired Events ({expiredEvents.length})
</summary>
...
</details>
```
3. **1-Click Reopen Action:**
- For naturally expired events (`is_active = TRUE`), render a dedicated
**`[ 🔄 Reopen (+1h) ]`** button calling `POST /api/events/:id/extend` with
`extendHours: 1`.
### Phase 6: Quality Gates & Network/Error Mock Testing
1. Run `deno test -A --no-check server/tests/events.test.ts` to assert all
extend, attendees, and 404/403 failure paths pass.
2. Run `deno test -A --no-check ui/ui_scripts.test.ts` to verify zero JavaScript
syntax or parsing errors.
3. Run `deno fmt`, `deno task lint`, `deno task check`, and
`deno test -A --no-check`.