- Moved `EventCockpitDeck` below main header in `SessionsPage.tsx` - Refactored `WorkshopDrawer.tsx` to strictly use a 2-state display toggle (`#eventCreateState` and `#eventHandoffState`) - Added `aria-label`s to copy buttons for accessibility - Configured `#status-banner` with `role="status"` and `aria-live="polite"` - Fixed mobile title text wrapping on `#createdEventTitle` - Fixed script emoji injection logic to prevent double emojis - Added JS reset logic in `closeDelegateDrawer` to restore drawer states and clear form data Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
178 lines
5.9 KiB
TypeScript
178 lines
5.9 KiB
TypeScript
import { AuthenticatedLayout } from "./AuthenticatedLayout.tsx";
|
||
import { EventCockpitDeck } from "./sessions/EventCockpitDeck.tsx";
|
||
import { DirectPassDrawer } from "./sessions/DirectPassDrawer.tsx";
|
||
import { WorkshopDrawer } from "./sessions/WorkshopDrawer.tsx";
|
||
import { ScopeModal } from "./sessions/ScopeModal.tsx";
|
||
import { SessionTable } from "./sessions/SessionTable.tsx";
|
||
import { SessionDeck } from "./sessions/SessionDeck.tsx";
|
||
import { SessionsScript } from "./sessions/SessionsScript.tsx";
|
||
|
||
export const SessionsPage = ({
|
||
sessions,
|
||
currentSessionId,
|
||
apps = [],
|
||
isAdmin = false,
|
||
eventPasses = [],
|
||
}: {
|
||
sessions: any[];
|
||
currentSessionId: string;
|
||
apps?: any[];
|
||
isAdmin?: boolean;
|
||
eventPasses?: any[];
|
||
}) => {
|
||
return (
|
||
<AuthenticatedLayout
|
||
title="Sessions & Delegations"
|
||
currentPath="/dashboard/sessions"
|
||
isAdmin={isAdmin}
|
||
>
|
||
<div
|
||
id="status-banner"
|
||
role="status"
|
||
aria-live="polite"
|
||
style="display: none; margin-bottom: 1rem; padding: 0.75rem 1rem; border-radius: var(--radius-md); font-size: 0.9rem;"
|
||
/>
|
||
|
||
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 1.5rem; flex-wrap: wrap; gap: 1rem;">
|
||
<div>
|
||
<h1 style="font-size: 1.75rem; font-weight: 700; margin: 0 0 0.5rem 0; color: var(--text-primary);">
|
||
Active Sessions & Passes
|
||
</h1>
|
||
<p style="color: var(--text-secondary); margin: 0; font-size: 0.95rem;">
|
||
Manage logins, mint 1:1 ephemeral links & CLI tokens, or launch
|
||
multi-claim workshop event passes.
|
||
</p>
|
||
</div>
|
||
|
||
<div style="display: flex; gap: 0.75rem; flex-wrap: wrap;">
|
||
<button
|
||
type="button"
|
||
class="btn-primary"
|
||
style="min-height: 42px; box-shadow: var(--shadow-sm); display: inline-flex; align-items: center; gap: 0.4rem;"
|
||
onclick="openDelegateDrawer()"
|
||
>
|
||
<span style="font-size: 1.1rem;">🔑</span>
|
||
<span>+ Delegate Session</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<EventCockpitDeck eventPasses={eventPasses} />
|
||
|
||
{/* Delegate Session Drawer */}
|
||
<div
|
||
id="delegateDrawer"
|
||
class="card"
|
||
style="display: none; border-left: 4px solid var(--primary); margin-bottom: 1.5rem;"
|
||
>
|
||
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.5rem;">
|
||
<div style="width: 100%;">
|
||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||
<h3
|
||
id="delegateDrawerTitle"
|
||
style="margin: 0 0 0.25rem 0; color: var(--text-primary);"
|
||
>
|
||
Create New Pass / Session
|
||
</h3>
|
||
<button
|
||
type="button"
|
||
onclick="closeDelegateDrawer()"
|
||
style="background: none; border: none; font-size: 1.3rem; color: var(--text-muted); cursor: pointer;"
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
|
||
<div style="display: flex; background: var(--surface-muted); padding: 4px; border-radius: var(--radius-sm); border: 1px solid var(--border-subtle); gap: 4px; margin-top: 1rem; margin-bottom: 1rem;">
|
||
<button
|
||
type="button"
|
||
id="tabBtnDirectPass"
|
||
class="delegate-tab-btn active"
|
||
onclick="switchDelegateTab('tabDirectPass')"
|
||
>
|
||
🔑 1:1 Direct Pass
|
||
</button>
|
||
<button
|
||
type="button"
|
||
id="tabBtnWorkshopPass"
|
||
class="delegate-tab-btn"
|
||
onclick="switchDelegateTab('tabWorkshopPass')"
|
||
>
|
||
🎟️ Multi-Claim Workshop Pass
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<DirectPassDrawer apps={apps} isAdmin={isAdmin} />
|
||
<WorkshopDrawer apps={apps} />
|
||
</div>
|
||
|
||
<ScopeModal apps={apps} />
|
||
|
||
{/* Desktop Table View (≥ 768px) */}
|
||
<SessionTable
|
||
sessions={sessions}
|
||
currentSessionId={currentSessionId}
|
||
/>
|
||
|
||
{/* Mobile Adaptive Cards View (< 768px) */}
|
||
<SessionDeck
|
||
sessions={sessions}
|
||
currentSessionId={currentSessionId}
|
||
/>
|
||
|
||
<style>
|
||
{`
|
||
@media (min-width: 768px) {
|
||
.desktop-only { display: block !important; }
|
||
.mobile-only { display: none !important; }
|
||
}
|
||
@media (max-width: 767px) {
|
||
.desktop-only { display: none !important; }
|
||
.mobile-only { display: flex !important; }
|
||
}
|
||
.pill-btn {
|
||
background: var(--surface-card);
|
||
border: 1px solid var(--border-subtle);
|
||
border-radius: var(--radius-full);
|
||
padding: 0.4rem 0.85rem;
|
||
font-size: 0.85rem;
|
||
font-weight: 600;
|
||
color: var(--text-secondary);
|
||
cursor: pointer;
|
||
transition: all 0.15s ease;
|
||
}
|
||
.pill-btn:hover {
|
||
border-color: var(--primary);
|
||
color: var(--primary);
|
||
}
|
||
.pill-btn.active {
|
||
background: var(--primary-light);
|
||
border-color: var(--primary);
|
||
color: var(--primary);
|
||
}
|
||
.delegate-tab-btn {
|
||
flex: 1;
|
||
padding: 0.5rem 0.75rem;
|
||
border-radius: var(--radius-sm);
|
||
border: none;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.15s;
|
||
background: transparent;
|
||
color: var(--text-secondary);
|
||
}
|
||
.delegate-tab-btn.active {
|
||
background: var(--surface-card);
|
||
color: var(--primary);
|
||
box-shadow: var(--shadow-xs);
|
||
}
|
||
`}
|
||
</style>
|
||
|
||
<SessionsScript />
|
||
</AuthenticatedLayout>
|
||
);
|
||
};
|