166 lines
7.3 KiB
Markdown
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`.
|