- Added a new cities table to the database to manage multiple cities independently. - Created a middleware to resolve city context based on X-City-Id header. - Updated routes and services to handle city-specific data for routes, stops, and alerts. - Implemented a CityContext in the frontend to manage active city state and provide city data across the application. - Added a CitySelector component for users to switch between cities. - Created a CitiesPage for admins to manage cities, including adding new cities with validation. - Updated various components and pages to reflect the active city context, ensuring data is displayed correctly based on the selected city. - Enhanced the schedule import functionality to restrict imports based on the active city.
89 lines
3.5 KiB
JavaScript
89 lines
3.5 KiB
JavaScript
import { BrowserRouter as Router, Routes, Route, useLocation, Navigate } from 'react-router-dom';
|
||
import { AuthProvider, useAuth } from './contexts/AuthContext';
|
||
import { ProtectedRoute } from './components/ProtectedRoute';
|
||
import AppLayout from './components/AppLayout';
|
||
import { PageLoader } from './components/AnimatedComponents';
|
||
import { CityProvider, useCity } from './contexts/CityContext';
|
||
|
||
// Pages
|
||
import LoginPage from './pages/LoginPage';
|
||
import Dashboard from './pages/Dashboard';
|
||
import RoutesPage from './pages/RoutesPage';
|
||
import RouteEditorPage from './pages/RouteEditorPage';
|
||
import StopsPage from './pages/StopsPage';
|
||
import SchedulesPage from './pages/SchedulesPage';
|
||
import ScheduleImportPage from './pages/ScheduleImportPage';
|
||
import QualityPage from './pages/QualityPage';
|
||
import HolidaysPage from './pages/HolidaysPage';
|
||
import AlertsPage from './pages/AlertsPage';
|
||
import UsersPage from './pages/UsersPage';
|
||
import ProfilePage from './pages/ProfilePage';
|
||
import CitiesPage from './pages/CitiesPage';
|
||
|
||
function App() {
|
||
return (
|
||
<Router>
|
||
<AuthProvider>
|
||
<AppContent />
|
||
</AuthProvider>
|
||
</Router>
|
||
);
|
||
}
|
||
|
||
function AppContent() {
|
||
const { isAuthenticated, loading } = useAuth();
|
||
|
||
if (loading) return <PageLoader />;
|
||
|
||
if (!isAuthenticated) {
|
||
return (
|
||
<Routes>
|
||
<Route path="/login" element={<LoginPage />} />
|
||
<Route path="*" element={<Navigate to="/login" replace />} />
|
||
</Routes>
|
||
);
|
||
}
|
||
|
||
return <CityProvider><CityWorkspace /></CityProvider>;
|
||
}
|
||
|
||
function CityWorkspace() {
|
||
const { loading, error, activeCity } = useCity();
|
||
|
||
if (loading) return <PageLoader />;
|
||
if (error || !activeCity) return <main className="login-surface"><div className="login-card max-w-md"><h1 className="text-xl font-semibold">Города недоступны</h1><p className="mt-2 text-gray-600">{error || 'В системе нет активных городов.'}</p></div></main>;
|
||
|
||
return <AppLayout>
|
||
<AnimatedRoutes cityId={activeCity.id} />
|
||
</AppLayout>;
|
||
}
|
||
|
||
function AnimatedRoutes({ cityId }) {
|
||
const location = useLocation();
|
||
const { isAdmin } = useAuth();
|
||
|
||
return (
|
||
<div key={`${cityId}:${location.pathname}`} className="page-transition">
|
||
<Routes location={location}>
|
||
<Route path="/" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
|
||
<Route path="/routes" element={<ProtectedRoute><RoutesPage /></ProtectedRoute>} />
|
||
<Route path="/routes/:id/edit" element={<ProtectedRoute><RouteEditorPage /></ProtectedRoute>} />
|
||
<Route path="/stops" element={<ProtectedRoute><StopsPage /></ProtectedRoute>} />
|
||
<Route path="/schedules" element={<ProtectedRoute><SchedulesPage /></ProtectedRoute>} />
|
||
<Route path="/schedule-import" element={<ProtectedRoute requireAdmin><ScheduleImportPage /></ProtectedRoute>} />
|
||
<Route path="/quality" element={<ProtectedRoute requireAdmin><QualityPage /></ProtectedRoute>} />
|
||
<Route path="/holidays" element={<ProtectedRoute><HolidaysPage /></ProtectedRoute>} />
|
||
<Route path="/alerts" element={<ProtectedRoute><AlertsPage /></ProtectedRoute>} />
|
||
<Route path="/profile" element={<ProtectedRoute><ProfilePage /></ProtectedRoute>} />
|
||
{isAdmin && <Route path="/cities" element={<ProtectedRoute requireAdmin><CitiesPage /></ProtectedRoute>} />}
|
||
{isAdmin && (
|
||
<Route path="/users" element={<ProtectedRoute requireAdmin><UsersPage /></ProtectedRoute>} />
|
||
)}
|
||
<Route path="*" element={<Navigate to="/" replace />} />
|
||
</Routes>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default App;
|