File size: 1,549 Bytes
f4854a1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { Navigate, useLocation } from 'react-router-dom';
import { useAuth } from '../../contexts/AuthContext';
import Loader from './Loader';

/**
 * ProtectedRoute — Guards routes based on authentication, email verification, and roles.
 * @param {Object} props
 * @param {React.ReactNode} props.children - Child components to render
 * @param {string[]} [props.allowedRoles] - Array of allowed roles (empty = any authenticated user)
 * @param {string} [props.redirectTo] - Where to redirect if not authenticated
 * @param {boolean} [props.requireVerified] - If true, user must have verified their email
 */
export default function ProtectedRoute({
  children,
  allowedRoles = [],
  redirectTo = '/login',
  requireVerified = true,
}) {
  const { currentUser, userProfile, loading } = useAuth();
  const location = useLocation();

  if (loading) {
    return <Loader fullScreen />;
  }

  // Not authenticated → send to login
  if (!currentUser) {
    return <Navigate to={redirectTo} state={{ from: location }} replace />;
  }

  // Authenticated but email not verified → send to verify-email page
  // Google sign-ins are already considered verified by Firebase (emailVerified = true)
  if (requireVerified && !currentUser.emailVerified) {
    return <Navigate to="/verify-email" state={{ from: location }} replace />;
  }

  // Check role if specified
  if (allowedRoles.length > 0 && userProfile) {
    if (!allowedRoles.includes(userProfile.role)) {
      return <Navigate to="/unauthorized" replace />;
    }
  }

  return children;
}