Школьники не должны придумывать пароль, чтобы пройти тест. Бэкенд уже
поддерживал это: POST /polls/{poll_id}/responses принимает user_id как
Optional, а Response.group_id/organization_id — самостоятельные nullable
снимки школы/класса, не завязанные на аккаунт. Не хватало только
фронтенда — все роуты были жёстко завёрнуты в ProtectedRoute с
обязательным JWT.
- AuthContext: параллельная "анонимная идентичность" (org+group в
localStorage, без токена и без запроса к API)
- ProtectedRoute пускает по токену ИЛИ анонимной сессии; новый
AccountRoute — строго по токену, для /my-tests, /profile,
/response/:id (у анонимной сессии нет истории — её негде хранить)
- Новая страница /anonymous — выбор школы+класса тем же
SearchableDropdown, что и в регистрации
- PollPage при отправке ответа берёт org/group из анонимной сессии,
если пользователь не залогинен
- HomePage скрывает "Мои тесты" и профиль для анонимов, добавлена
кнопка выхода из анонимного режима
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
47 lines
2.0 KiB
TypeScript
47 lines
2.0 KiB
TypeScript
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
|
|
import { AuthProvider } from "./auth/AuthContext";
|
|
import { ThemeProvider } from "./theme/ThemeContext";
|
|
import { ProtectedRoute, AccountRoute } from "./components/ProtectedRoute";
|
|
import { LoginPage } from "./pages/LoginPage";
|
|
import { RegisterPage } from "./pages/RegisterPage";
|
|
import { AnonymousEntryPage } from "./pages/AnonymousEntryPage";
|
|
import { HomePage } from "./pages/HomePage";
|
|
import { TestListPage } from "./pages/TestListPage";
|
|
import { PollPage } from "./pages/PollPage";
|
|
import { MyTestsPage } from "./pages/MyTestsPage";
|
|
import { ResponsePage } from "./pages/ResponsePage";
|
|
import { ProfilePage } from "./pages/ProfilePage";
|
|
|
|
// Доступно и по токену, и анонимно (школа+класс без аккаунта).
|
|
function protect(el: React.ReactNode) {
|
|
return <ProtectedRoute>{el}</ProtectedRoute>;
|
|
}
|
|
|
|
// Требует настоящий аккаунт — история и профиль анонимусам недоступны.
|
|
function account(el: React.ReactNode) {
|
|
return <AccountRoute>{el}</AccountRoute>;
|
|
}
|
|
|
|
export default function App() {
|
|
return (
|
|
<ThemeProvider>
|
|
<AuthProvider>
|
|
<BrowserRouter>
|
|
<Routes>
|
|
<Route path="/login" element={<LoginPage />} />
|
|
<Route path="/register" element={<RegisterPage />} />
|
|
<Route path="/anonymous" element={<AnonymousEntryPage />} />
|
|
<Route path="/" element={protect(<HomePage />)} />
|
|
<Route path="/tests" element={protect(<TestListPage />)} />
|
|
<Route path="/poll/:pollId" element={protect(<PollPage />)} />
|
|
<Route path="/my-tests" element={account(<MyTestsPage />)} />
|
|
<Route path="/response/:responseId" element={account(<ResponsePage />)} />
|
|
<Route path="/profile" element={account(<ProfilePage />)} />
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
</BrowserRouter>
|
|
</AuthProvider>
|
|
</ThemeProvider>
|
|
);
|
|
}
|