Files
dashboard/frontend/src/components/auth/ProtectedRoute.tsx
Matthias Hochmeister 2306741c4d feat: dashboard widgets, auth fix, profile names, dynamic groups
- 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>
2026-03-03 10:28:31 +01:00

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;