Files
resolutionflow/frontend/src/router.tsx
chihlasm bd12ced5ee feat: analytics dashboards & two-tier feedback system (#78)
* docs: add analytics & user feedback design document

Covers team analytics, personal analytics, flow analytics,
step-level thumbs up/down feedback, and flow CSAT ratings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add analytics & feedback implementation plan

12-task TDD plan covering session ratings, step feedback,
team/personal/flow analytics endpoints, and frontend pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add session_ratings table and analytics indexes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add SessionRating model and analytics schemas

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add session CSAT rating endpoint with tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add step thumbs feedback and /ratings alias routes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add team, personal, and flow analytics endpoints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add recharts, analytics types, and API client

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add inline step thumbs up/down feedback during sessions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add CSAT rating modal after session completion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add Team Analytics page with charts and leaderboards

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add Flow Analytics panel with step dropoff and CSAT data

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add My Analytics page with personal stats and charts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 15:23:14 -05:00

338 lines
9.1 KiB
TypeScript

import { createBrowserRouter } from 'react-router-dom'
import { lazy, Suspense } from 'react'
import { AppLayout, ProtectedRoute } from '@/components/layout'
import { RouteError } from '@/components/common/RouteError'
import { PageLoader } from '@/components/common/PageLoader'
import {
LoginPage,
RegisterPage,
} from '@/pages'
// Public pages
const SharedSessionPage = lazy(() => import('@/pages/SharedSessionPage'))
// Standalone auth pages
const ChangePasswordPage = lazy(() => import('@/pages/ChangePasswordPage'))
const ForgotPasswordPage = lazy(() => import('@/pages/ForgotPasswordPage'))
const ResetPasswordPage = lazy(() => import('@/pages/ResetPasswordPage'))
// Lazy load heavy pages for code splitting
const QuickStartPage = lazy(() => import('@/pages/QuickStartPage'))
const TreeLibraryPage = lazy(() => import('@/pages/TreeLibraryPage'))
const MyTreesPage = lazy(() => import('@/pages/MyTreesPage'))
const TreeNavigationPage = lazy(() => import('@/pages/TreeNavigationPage'))
const TreeEditorPage = lazy(() => import('@/pages/TreeEditorPage'))
const ProceduralEditorPage = lazy(() => import('@/pages/ProceduralEditorPage'))
const ProceduralNavigationPage = lazy(() => import('@/pages/ProceduralNavigationPage'))
const SessionHistoryPage = lazy(() => import('@/pages/SessionHistoryPage'))
const SessionDetailPage = lazy(() => import('@/pages/SessionDetailPage'))
const MySharesPage = lazy(() => import('@/pages/MySharesPage'))
const TeamAnalyticsPage = lazy(() => import('@/pages/TeamAnalyticsPage'))
const MyAnalyticsPage = lazy(() => import('@/pages/MyAnalyticsPage'))
const AccountSettingsPage = lazy(() => import('@/pages/AccountSettingsPage'))
// Admin pages
const AdminLayout = lazy(() => import('@/components/admin/AdminLayout'))
const AdminDashboardPage = lazy(() => import('@/pages/admin/DashboardPage'))
const AdminUsersPage = lazy(() => import('@/pages/admin/UsersPage'))
const AdminUserDetailPage = lazy(() => import('@/pages/admin/UserDetailPage'))
const AdminInviteCodesPage = lazy(() => import('@/pages/admin/InviteCodesPage'))
const AdminAuditLogsPage = lazy(() => import('@/pages/admin/AuditLogsPage'))
const AdminPlanLimitsPage = lazy(() => import('@/pages/admin/PlanLimitsPage'))
const AdminFeatureFlagsPage = lazy(() => import('@/pages/admin/FeatureFlagsPage'))
const AdminSettingsPage = lazy(() => import('@/pages/admin/SettingsPage'))
const AdminGlobalCategoriesPage = lazy(() => import('@/pages/admin/GlobalCategoriesPage'))
// Account pages
const AccountLayout = lazy(() => import('@/components/account/AccountLayout'))
const TeamCategoriesPage = lazy(() => import('@/pages/account/TeamCategoriesPage'))
export const router = createBrowserRouter([
{
path: '/login',
element: <LoginPage />,
errorElement: <RouteError />,
},
{
path: '/register',
element: <RegisterPage />,
errorElement: <RouteError />,
},
{
path: '/forgot-password',
element: (
<Suspense fallback={<PageLoader />}>
<ForgotPasswordPage />
</Suspense>
),
errorElement: <RouteError />,
},
{
path: '/reset-password',
element: (
<Suspense fallback={<PageLoader />}>
<ResetPasswordPage />
</Suspense>
),
errorElement: <RouteError />,
},
{
path: '/share/:shareToken',
element: (
<Suspense fallback={<PageLoader />}>
<SharedSessionPage />
</Suspense>
),
errorElement: <RouteError />,
},
{
path: '/change-password',
element: (
<ProtectedRoute>
<Suspense fallback={<PageLoader />}>
<ChangePasswordPage />
</Suspense>
</ProtectedRoute>
),
errorElement: <RouteError />,
},
{
path: '/',
element: (
<ProtectedRoute>
<AppLayout />
</ProtectedRoute>
),
errorElement: <RouteError />,
children: [
{
index: true,
element: (
<Suspense fallback={<PageLoader />}>
<QuickStartPage />
</Suspense>
),
},
{
path: 'trees',
element: (
<Suspense fallback={<PageLoader />}>
<TreeLibraryPage />
</Suspense>
),
},
{
path: 'my-trees',
element: (
<Suspense fallback={<PageLoader />}>
<MyTreesPage />
</Suspense>
),
},
{
path: 'trees/new',
element: (
<Suspense fallback={<PageLoader />}>
<TreeEditorPage />
</Suspense>
),
},
{
path: 'trees/:id/edit',
element: (
<Suspense fallback={<PageLoader />}>
<TreeEditorPage />
</Suspense>
),
},
{
path: 'flows/new',
element: (
<Suspense fallback={<PageLoader />}>
<ProceduralEditorPage />
</Suspense>
),
},
{
path: 'flows/:id/edit',
element: (
<Suspense fallback={<PageLoader />}>
<ProceduralEditorPage />
</Suspense>
),
},
{
path: 'flows/:id/navigate',
element: (
<Suspense fallback={<PageLoader />}>
<ProceduralNavigationPage />
</Suspense>
),
},
{
path: 'trees/:id/navigate',
element: (
<Suspense fallback={<PageLoader />}>
<TreeNavigationPage />
</Suspense>
),
},
{
path: 'sessions',
element: (
<Suspense fallback={<PageLoader />}>
<SessionHistoryPage />
</Suspense>
),
},
{
path: 'sessions/:id',
element: (
<Suspense fallback={<PageLoader />}>
<SessionDetailPage />
</Suspense>
),
},
{
path: 'shares',
element: (
<Suspense fallback={<PageLoader />}>
<MySharesPage />
</Suspense>
),
},
{
path: 'analytics',
element: (
<Suspense fallback={<PageLoader />}>
<TeamAnalyticsPage />
</Suspense>
),
},
{
path: 'analytics/me',
element: (
<Suspense fallback={<PageLoader />}>
<MyAnalyticsPage />
</Suspense>
),
},
// Admin routes
{
path: 'admin',
element: (
<Suspense fallback={<PageLoader />}>
<ProtectedRoute requiredRole="super_admin">
<AdminLayout />
</ProtectedRoute>
</Suspense>
),
children: [
{
index: true,
element: (
<Suspense fallback={<PageLoader />}>
<AdminDashboardPage />
</Suspense>
),
},
{
path: 'users',
element: (
<Suspense fallback={<PageLoader />}>
<AdminUsersPage />
</Suspense>
),
},
{
path: 'users/:userId',
element: (
<Suspense fallback={<PageLoader />}>
<AdminUserDetailPage />
</Suspense>
),
},
{
path: 'invite-codes',
element: (
<Suspense fallback={<PageLoader />}>
<AdminInviteCodesPage />
</Suspense>
),
},
{
path: 'audit-logs',
element: (
<Suspense fallback={<PageLoader />}>
<AdminAuditLogsPage />
</Suspense>
),
},
{
path: 'plan-limits',
element: (
<Suspense fallback={<PageLoader />}>
<AdminPlanLimitsPage />
</Suspense>
),
},
{
path: 'feature-flags',
element: (
<Suspense fallback={<PageLoader />}>
<AdminFeatureFlagsPage />
</Suspense>
),
},
{
path: 'settings',
element: (
<Suspense fallback={<PageLoader />}>
<AdminSettingsPage />
</Suspense>
),
},
{
path: 'categories',
element: (
<Suspense fallback={<PageLoader />}>
<AdminGlobalCategoriesPage />
</Suspense>
),
},
],
},
// Account routes
{
path: 'account',
element: (
<Suspense fallback={<PageLoader />}>
<AccountLayout />
</Suspense>
),
children: [
{
index: true,
element: (
<Suspense fallback={<PageLoader />}>
<AccountSettingsPage />
</Suspense>
),
},
{
path: 'categories',
element: (
<Suspense fallback={<PageLoader />}>
<ProtectedRoute requiredRole="owner">
<TeamCategoriesPage />
</ProtectedRoute>
</Suspense>
),
},
],
},
],
},
])
export default router