auth-yes/ui/components/SessionsPage.tsx
google-labs-jules[bot] 61789f1d45 feat: phase 6 final polish for sessions and events
- implemented universal ingress credential rotation (slug + pin)
- fixed event extension logic (`GREATEST(expires_at, NOW())`)
- added UI formatter logic for natural dates (`formatNaturalExpiry`, `formatNaturalJoinTime`)
- updated event cards to bounded 2-row compact cards
- consolidated CLI expanding snippets
- overhauled WAI-ARIA support for delegation drawers
- removed legacy "Dismiss" mock buttons for cleanly styled "OK" buttons
- updated tests and ensured pure zero-dependency SSR JSX compatibility

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

212 lines
7.3 KiB
TypeScript

import { AuthenticatedLayout } from "./AuthenticatedLayout.tsx";
import { EventCockpitDeck } from "./sessions/EventCockpitDeck.tsx";
import { EventGuestsDrawer } from "./sessions/EventGuestsDrawer.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);">
Sessions & Events
</h1>
<p style="color: var(--text-secondary); margin: 0; font-size: 0.95rem;">
Manage logins, mint 1:1 delegated tokens, or launch multi-claim
workshop events.
</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; justify-content: center;"
onclick="openDelegateDrawer()"
>
Delegate Session
</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;">
<h2
id="delegateDrawerTitle"
style="margin: 0 0 0.25rem 0; color: var(--text-primary); font-size: 1.25rem;"
>
Delegate Session
</h2>
<button
type="button"
onclick="closeDelegateDrawer()"
style="background: none; border: none; font-size: 1.3rem; color: var(--text-muted); cursor: pointer;"
>
&times;
</button>
</div>
<p style="color: var(--text-secondary); margin: 0; font-size: 0.9rem;">
Mint a 1:1 delegated token or launch a multi-seat workshop event.
</p>
<div
role="tablist"
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"
role="tab"
aria-selected="true"
id="tabBtnDirectPass"
class="delegate-tab-btn active"
onclick="switchDelegateTab('tabDirectPass')"
style="display: flex; flex-direction: column; align-items: center; gap: 2px;"
>
<span style="font-size: 0.95rem; font-weight: 700;">
Single Session
</span>
<span style="font-size: 0.75rem; font-weight: 400; opacity: 0.85;">
For agents, CI/CD, or 1:1 delegation
</span>
</button>
<button
type="button"
role="tab"
aria-selected="false"
id="tabBtnWorkshopPass"
class="delegate-tab-btn"
onclick="switchDelegateTab('tabWorkshopPass')"
style="display: flex; flex-direction: column; align-items: center; gap: 2px;"
>
<span style="font-size: 0.95rem; font-weight: 700;">
Multi-Claim Event
</span>
<span style="font-size: 0.75rem; font-weight: 400; opacity: 0.85;">
For workshops, teams & guest pools
</span>
</button>
</div>
</div>
</div>
<DirectPassDrawer apps={apps} isAdmin={isAdmin} />
<WorkshopDrawer apps={apps} />
</div>
<EventGuestsDrawer />
<ScopeModal apps={apps} />
<h2 style="font-size: 1.25rem; margin-top: 2rem; margin-bottom: 0.25rem; color: var(--text-primary);">
Sessions
</h2>
<p style="color: var(--text-secondary); margin-bottom: 1rem; font-size: 0.95rem;">
Direct device logins, passkey authentications, and delegated agent
tokens.
</p>
{/* 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);
opacity: 0.75;
}
.delegate-tab-btn.active {
background: var(--primary);
color: #ffffff;
box-shadow: var(--shadow-xs);
opacity: 1;
}
`}
</style>
<SessionsScript />
</AuthenticatedLayout>
);
};