app/src/AppRoutes.tsx
kcar 7a01b3e8f6 Merge remote-tracking branch 'origin/master' into agent/s4-11-marking-results
# Conflicts:
#	src/AppRoutes.tsx
#	src/pages/exam/index.ts
#	src/services/exam/examRepository.ts
#	src/types/exam.types.ts
2026-06-07 19:58:38 +01:00

211 lines
7.6 KiB
TypeScript

import React from 'react';
import { Routes, Route, useLocation, Outlet, Navigate } from 'react-router-dom';
import { useAuth } from './contexts/AuthContext';
import { useUser } from './contexts/UserContext';
import Layout from './pages/Layout';
import LoginPage from './pages/auth/loginPage';
import SignupPage from './pages/auth/signupPage';
import SinglePlayerPage from './pages/tldraw/singlePlayerPage';
import MultiplayerUser from './pages/tldraw/multiplayerUser';
import { ExamDashboardPage, ExamMarkingPage, ExamResultsPage, ExamTemplateSetupPage, MarkSchemePage } from './pages/exam';
import { ErrorBoundary } from './components/ErrorBoundary';
import CalendarPage from './pages/user/calendarPage';
import SettingsPage from './pages/user/settingsPage';
import TLDrawCanvas from './pages/tldraw/TLDrawCanvas';
import AdminDashboard from './pages/auth/adminPage';
import PlatformAdminPage from './pages/auth/PlatformAdminPage';
import TLDrawDevPage from './pages/tldraw/devPlayerPage';
import DevPage from './pages/tldraw/devPage';
import TeacherPlanner from './pages/react-flow/teacherPlanner';
import MorphicPage from './pages/morphicPage';
import NotFound from './pages/user/NotFound';
import NotFoundPublic from './pages/NotFoundPublic';
import ShareHandler from './pages/tldraw/ShareHandler';
import SearxngPage from './pages/searxngPage';
import SimpleUploadTest from './pages/dev/SimpleUploadTest';
import { logger } from './debugConfig';
import { CircularProgress } from '@mui/material';
import { CCDocumentIntelligence } from './pages/tldraw/CCDocumentIntelligence/CCDocumentIntelligence';
import DashboardPage from './pages/user/dashboardPage';
// Timetable Module Pages
import {
TimetablePage,
TimetableListPage,
ClassesPage,
LessonPage,
TaughtLessonsPage,
MyClassesPage,
EnrollmentRequestsPage,
StaffManagerPage,
StudentManagerPage,
SchoolSettingsPage,
ClassDetailPage,
StudentLessonsPage,
LessonPlansPage,
LessonPlanDetailPage,
} from './pages/timetable';
const FullContextRoutes: React.FC = () => {
const { isInitialized: isUserInitialized } = useUser();
if (!isUserInitialized) {
return (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100%',
width: '100%'
}}
>
<CircularProgress />
</div>
);
}
return <Outlet />;
};
const RequireAuth: React.FC = () => {
const { user, isAuthResolving } = useAuth();
if (isAuthResolving) {
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh'
}}
>
<CircularProgress />
</div>
);
}
if (!user) {
return <Navigate to="/login" replace />;
}
return <Outlet />;
};
const AppRoutes: React.FC = () => {
const { user, user_role, loading: isAuthLoading } = useAuth();
const location = useLocation();
const platformAdminRoles = ['super_admin', 'cc_admin', 'cc_developer'];
const isPlatformAdmin = !!user && platformAdminRoles.includes(user_role ?? '');
// Debug log for routing
logger.debug('routing', '🔄 Rendering routes', {
hasUser: !!user,
userId: user?.id,
userEmail: user?.email,
currentPath: location.pathname,
authStatus: {
isLoading: isAuthLoading,
},
});
// Show loading state while initializing
if (isAuthLoading) {
return (
<Layout>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100vh',
}}
>
<CircularProgress />
</div>
</Layout>
);
}
return (
<Layout>
<Routes>
{/* Public routes */}
<Route
path="/"
element={user ? <DashboardPage /> : <TLDrawCanvas />}
/>
<Route path="/login" element={<LoginPage />} />
<Route path="/signup" element={<SignupPage />} />
<Route path="/share" element={<ShareHandler />} />
{/* Lightweight authenticated routes */}
<Route
path="/dashboard"
element={user ? <DashboardPage /> : <Navigate to="/login" replace />}
/>
{/* Super Admin only routes */}
<Route
path="/admin"
element={
!user ? (
<Navigate to="/login" replace state={{ from: location }} />
) : isPlatformAdmin ? (
<PlatformAdminPage />
) : (
<Navigate to="/dashboard" replace />
)
}
/>
{/* Authentication only routes - only render if all contexts are initialized */}
<Route element={<RequireAuth />}>
<Route element={<FullContextRoutes />}>
{/* Timetable Module Routes */}
<Route path="/timetable" element={<TimetableListPage />} />
<Route path="/timetable/:timetableId" element={<TimetablePage />} />
<Route path="/classes" element={<ClassesPage />} />
<Route path="/my-classes" element={<MyClassesPage />} />
<Route path="/classes/:classId" element={<ClassDetailPage />} />
<Route path="/timetable/classes/:classId" element={<ClassDetailPage />} />
<Route path="/student-lessons" element={<StudentLessonsPage />} />
<Route path="/lesson-plans" element={<LessonPlansPage />} />
<Route path="/lesson-plans/:planId" element={<LessonPlanDetailPage />} />
<Route path="/enrollment-requests" element={<EnrollmentRequestsPage />} />
<Route path="/lessons/:lessonId" element={<LessonPage />} />
<Route path="/my-lessons" element={<TaughtLessonsPage />} />
<Route path="/staff-manager" element={<StaffManagerPage />} />
<Route path="/student-manager" element={<StudentManagerPage />} />
<Route path="/school-settings" element={<SchoolSettingsPage />} />
{/* Existing Routes */}
<Route path="/search" element={<SearxngPage />} />
<Route path="/teacher-planner" element={<TeacherPlanner />} />
<Route path="/exam-marker" element={<ErrorBoundary><ExamDashboardPage /></ErrorBoundary>} />
<Route path="/exam-marker/:templateId/setup" element={<ErrorBoundary><ExamTemplateSetupPage /></ErrorBoundary>} />
<Route path="/exam-marker/:templateId/marks" element={<ErrorBoundary><MarkSchemePage /></ErrorBoundary>} />
<Route path="/exam-marker/:batchId/mark" element={<ErrorBoundary><ExamMarkingPage /></ErrorBoundary>} />
<Route path="/exam-marker/:batchId/results" element={<ErrorBoundary><ExamResultsPage /></ErrorBoundary>} />
<Route path="/doc-intelligence/:fileId" element={<CCDocumentIntelligence />} />
<Route path="/morphic" element={<MorphicPage />} />
<Route path="/tldraw-dev" element={<TLDrawDevPage />} />
<Route path="/dev" element={<DevPage />} />
<Route path="/dev/upload-test" element={<SimpleUploadTest />} />
<Route path="/single-player" element={<SinglePlayerPage />} />
<Route path="/multiplayer" element={<MultiplayerUser />} />
<Route path="/calendar" element={<CalendarPage />} />
<Route path="/settings" element={<SettingsPage />} />
</Route>
</Route>
{/* Fallback route - authenticated users go to dashboard, unauthenticated see public 404 */}
<Route path="*" element={user ? <Navigate to="/dashboard" replace /> : <NotFoundPublic />} />
</Routes>
</Layout>
);
};
export default AppRoutes;