- Add VehicleDashboardCard: self-contained widget modelled after AtemschutzDashboardCard, shows einsatzbereit ratio and inspection warnings inline; replaces StatsCard + InspectionAlerts in Dashboard - Add EquipmentDashboardCard: consolidated equipment status widget showing only aggregated counts (no per-item listing); replaces EquipmentAlerts component in Dashboard - Fix auth race condition: add authInitialized flag to api.ts so 401 responses during initial token validation no longer trigger a spurious redirect to /login; save intended destination before login redirect and restore it after successful auth callback - Fix profile firstname/lastname: add extractNames() helper to auth.controller.ts that falls back to splitting userinfo.name when Authentik does not provide separate given_name/family_name fields; applied on both create and update paths - Dynamic groups endpoint: replace hardcoded KNOWN_GROUPS array in events.controller.ts with a DB query (SELECT DISTINCT unnest (authentik_groups) FROM users); known slugs get German labels via lookup map, unknown slugs are humanized automatically Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
44 lines
1.2 KiB
TypeScript
44 lines
1.2 KiB
TypeScript
import React from 'react';
|
|
import { Navigate } from 'react-router-dom';
|
|
import { useAuth } from '../../contexts/AuthContext';
|
|
import { Box, CircularProgress, Typography } from '@mui/material';
|
|
|
|
interface ProtectedRouteProps {
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
|
|
const { isAuthenticated, isLoading } = useAuth();
|
|
|
|
// Show loading spinner while checking authentication
|
|
if (isLoading) {
|
|
return (
|
|
<Box
|
|
sx={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
minHeight: '100vh',
|
|
gap: 2,
|
|
}}
|
|
>
|
|
<CircularProgress size={60} />
|
|
<Typography variant="h6" color="text.secondary">
|
|
Authentifizierung wird überprüft...
|
|
</Typography>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
// If not authenticated, redirect to login
|
|
if (!isAuthenticated) {
|
|
return <Navigate to="/login" replace state={{ from: window.location.pathname + window.location.search }} />;
|
|
}
|
|
|
|
// User is authenticated, render children
|
|
return <>{children}</>;
|
|
};
|
|
|
|
export default ProtectedRoute;
|