65 lines
1.5 KiB
TypeScript
65 lines
1.5 KiB
TypeScript
|
|
import { useEffect, type ReactNode } from 'react';
|
||
|
|
import { Spin } from 'antd';
|
||
|
|
import { useAuthStore } from '@/stores/authStore';
|
||
|
|
|
||
|
|
interface ProtectedRouteProps {
|
||
|
|
children: ReactNode;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Wrapper component that ensures the user is authenticated
|
||
|
|
* Shows loading spinner while checking auth status
|
||
|
|
* Redirects to login if not authenticated
|
||
|
|
*/
|
||
|
|
export function ProtectedRoute({ children }: ProtectedRouteProps) {
|
||
|
|
const { isAuthenticated, isLoading, login, refreshUser } = useAuthStore();
|
||
|
|
|
||
|
|
// Check auth on mount
|
||
|
|
useEffect(() => {
|
||
|
|
refreshUser();
|
||
|
|
}, [refreshUser]);
|
||
|
|
|
||
|
|
// Show loading spinner while checking auth
|
||
|
|
if (isLoading) {
|
||
|
|
return (
|
||
|
|
<div
|
||
|
|
style={{
|
||
|
|
display: 'flex',
|
||
|
|
justifyContent: 'center',
|
||
|
|
alignItems: 'center',
|
||
|
|
height: '100vh',
|
||
|
|
flexDirection: 'column',
|
||
|
|
gap: 16,
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<Spin size="large" />
|
||
|
|
<span style={{ color: '#666' }}>Logger ind...</span>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Redirect to login if not authenticated
|
||
|
|
if (!isAuthenticated) {
|
||
|
|
login();
|
||
|
|
return (
|
||
|
|
<div
|
||
|
|
style={{
|
||
|
|
display: 'flex',
|
||
|
|
justifyContent: 'center',
|
||
|
|
alignItems: 'center',
|
||
|
|
height: '100vh',
|
||
|
|
flexDirection: 'column',
|
||
|
|
gap: 16,
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<Spin size="large" />
|
||
|
|
<span style={{ color: '#666' }}>Omdirigerer til login...</span>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return <>{children}</>;
|
||
|
|
}
|
||
|
|
|
||
|
|
export default ProtectedRoute;
|