ProtectedRoute.tsx 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. import React, { useEffect } from 'react';
  2. import { useNavigate } from 'react-router';
  3. import { useAuth } from '../hooks/AuthProvider';
  4. import { Skeleton } from '@/client/components/ui/skeleton';
  5. import { Card, CardContent } from '@/client/components/ui/card';
  6. export const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
  7. const { isAuthenticated, isLoading } = useAuth();
  8. const navigate = useNavigate();
  9. useEffect(() => {
  10. // 只有在加载完成且未认证时才重定向
  11. if (!isLoading && !isAuthenticated) {
  12. navigate('/login', { replace: true });
  13. }
  14. }, [isAuthenticated, isLoading, navigate]);
  15. // 显示加载状态,直到认证检查完成
  16. if (isLoading) {
  17. return (
  18. <div className="flex justify-center items-center min-h-screen bg-gradient-to-br from-slate-50 to-slate-100">
  19. <Card className="border-0 shadow-lg">
  20. <CardContent className="flex flex-col items-center space-y-4 py-12 px-8">
  21. <div className="relative">
  22. <Skeleton className="h-12 w-12 rounded-full" />
  23. <div className="absolute inset-0 rounded-full bg-primary/20 animate-pulse" />
  24. </div>
  25. <div className="space-y-2 text-center">
  26. <Skeleton className="h-4 w-32" />
  27. <Skeleton className="h-3 w-24" />
  28. </div>
  29. </CardContent>
  30. </Card>
  31. </div>
  32. );
  33. }
  34. // 如果未认证且不再加载中,不显示任何内容(等待重定向)
  35. if (!isAuthenticated) {
  36. return null;
  37. }
  38. return children;
  39. };