auth-yes/ui/components/SessionsPage.tsx
google-labs-jules[bot] d86642ce31 feat: Sessions UI overhaul and backend revocation fix
- Update `DELETE /api/sessions/:id` in `server/routes/sessions.ts` to allow event creators to delete guests' sessions.
- Update page hierarchy and top headings in `ui/components/SessionsPage.tsx`.
- Refactor `EventAttendeesDrawer.tsx` to `EventGuestsDrawer.tsx` as a fixed slide-over overlay.
- Add multi-event compact view toggle with `localStorage` persistence in `EventCockpitDeck.tsx`.
- Standardize dynamic countdown pills across `EventCockpitDeck.tsx`, `EventGuestsDrawer.tsx`, `SessionDeck.tsx`, and `SessionTable.tsx`.
- Optimize mobile session deck in `SessionDeck.tsx`.

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

191 lines
6.4 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 & 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; justify-content: center;"
onclick="openDelegateDrawer()"
>
Delegate Session
</button>
</div>
</div>
<h2 style="font-size: 1.25rem; margin-top: 2rem; margin-bottom: 1rem; color: var(--text-primary);">
Event Passes
</h2>
<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;"
>
&times;
</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>
<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);
}
.delegate-tab-btn.active {
background: var(--surface-card);
color: var(--primary);
box-shadow: var(--shadow-xs);
}
`}
</style>
<SessionsScript />
</AuthenticatedLayout>
);
};