feat(l1): register /l1/* routes + L1RouteGuard + page stubs

L1RouteGuard wraps the new routes and redirects users without
canUseL1Surface back to /. Page components are stubs in this task
(real UI in T21-T24): L1Dashboard, L1WalkPage, L1DraftsPage,
L1TicketsPage.

Routes: /l1, /l1/walk/:sessionId, /l1/drafts, /l1/tickets — all gated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-28 14:03:26 -04:00
parent fbe25b3d68
commit d0561be6a1
6 changed files with 74 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
import { Navigate } from 'react-router-dom'
import { usePermissions } from '@/hooks/usePermissions'
export function L1RouteGuard({ children }: { children: React.ReactNode }) {
const { canUseL1Surface } = usePermissions()
if (!canUseL1Surface) {
return <Navigate to="/" replace />
}
return <>{children}</>
}

View File

@@ -0,0 +1,13 @@
import { PageMeta } from '@/components/common/PageMeta'
export default function L1Dashboard() {
return (
<div className="overflow-y-auto h-full">
<PageMeta title="L1 Workspace" />
<div className="max-w-4xl mx-auto px-6 pt-12 pb-12">
<h1 className="font-heading text-2xl font-bold">L1 Workspace</h1>
<p className="text-muted-foreground mt-2">Loading</p>
</div>
</div>
)
}

View File

@@ -0,0 +1,13 @@
import { PageMeta } from '@/components/common/PageMeta'
export default function L1DraftsPage() {
return (
<div className="overflow-y-auto h-full">
<PageMeta title="My Drafts" />
<div className="max-w-4xl mx-auto px-6 pt-12 pb-12">
<h1 className="font-heading text-2xl font-bold">My Drafts</h1>
<p className="text-muted-foreground mt-2">Loading</p>
</div>
</div>
)
}

View File

@@ -0,0 +1,13 @@
import { PageMeta } from '@/components/common/PageMeta'
export default function L1TicketsPage() {
return (
<div className="overflow-y-auto h-full">
<PageMeta title="L1 Tickets" />
<div className="max-w-4xl mx-auto px-6 pt-12 pb-12">
<h1 className="font-heading text-2xl font-bold">L1 Tickets</h1>
<p className="text-muted-foreground mt-2">Loading</p>
</div>
</div>
)
}

View File

@@ -0,0 +1,13 @@
import { PageMeta } from '@/components/common/PageMeta'
export default function L1WalkPage() {
return (
<div className="overflow-y-auto h-full">
<PageMeta title="L1 Walk" />
<div className="max-w-4xl mx-auto px-6 pt-12 pb-12">
<h1 className="font-heading text-2xl font-bold">L1 Walk</h1>
<p className="text-muted-foreground mt-2">Loading</p>
</div>
</div>
)
}

View File

@@ -7,6 +7,7 @@ import { RouteError } from '@/components/common/RouteError'
import { ErrorBoundary } from '@/components/common/ErrorBoundary'
import { PageLoader } from '@/components/common/PageLoader'
import { lazyWithRetry } from '@/lib/lazyWithRetry'
import { L1RouteGuard } from '@/components/layout/L1RouteGuard'
const sentryCreateBrowserRouter = Sentry.wrapCreateBrowserRouterV7(createBrowserRouter)
import {
@@ -95,6 +96,12 @@ const AdminSurveyInvitesPage = lazyWithRetry(() => import('@/pages/admin/SurveyI
const AdminSurveyResponsesPage = lazyWithRetry(() => import('@/pages/admin/SurveyResponsesPage'))
const AdminGalleryManagementPage = lazyWithRetry(() => import('@/pages/admin/GalleryManagementPage'))
// L1 workspace pages
const L1Dashboard = lazyWithRetry(() => import('@/pages/l1/L1Dashboard'))
const L1WalkPage = lazyWithRetry(() => import('@/pages/l1/L1WalkPage'))
const L1DraftsPage = lazyWithRetry(() => import('@/pages/l1/L1DraftsPage'))
const L1TicketsPage = lazyWithRetry(() => import('@/pages/l1/L1TicketsPage'))
// Account pages
const AccountLayout = lazyWithRetry(() => import('@/components/account/AccountLayout'))
const ProfileSettingsPage = lazyWithRetry(() => import('@/pages/account/ProfileSettingsPage'))
@@ -284,6 +291,11 @@ export const router = sentryCreateBrowserRouter([
{ path: 'welcome/step-1', element: page(WelcomeStep1) },
{ path: 'welcome/step-2', element: page(WelcomeStep2) },
{ path: 'welcome/step-3', element: page(WelcomeStep3) },
// L1 workspace routes — gated by canUseL1Surface
{ path: 'l1', element: <L1RouteGuard>{page(L1Dashboard)}</L1RouteGuard> },
{ path: 'l1/walk/:sessionId', element: <L1RouteGuard>{page(L1WalkPage)}</L1RouteGuard> },
{ path: 'l1/drafts', element: <L1RouteGuard>{page(L1DraftsPage)}</L1RouteGuard> },
{ path: 'l1/tickets', element: <L1RouteGuard>{page(L1TicketsPage)}</L1RouteGuard> },
// Admin routes
{
path: 'admin',