diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index 329a223..4fd48c7 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -1,5 +1,5 @@ import { useState, useCallback } from "react"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useSearchParams } from "react-router-dom"; import { useDispatch } from "react-redux"; import { Button } from "../components/common/button"; import Input from "../components/common/input"; @@ -11,6 +11,7 @@ import { loginUser } from "../features/auth/authThunks"; const Login = () => { const navigate = useNavigate(); const dispatch = useDispatch(); + const [searchParams] = useSearchParams(); const [email, setEmail] = useState(""); const [password, setPassword] = useState("········"); @@ -30,7 +31,10 @@ const Login = () => { const result = await dispatch(loginUser({ email, password })); if (result.payload) { - navigate("/dashboard"); + // Check for redirect query parameter + const redirectParam = searchParams.get('redirect'); + const redirectPath = redirectParam ? decodeURIComponent(redirectParam) : '/dashboard'; + navigate(redirectPath); } else if (result.payload?.message) { setError(result.payload.message); } else { @@ -41,7 +45,7 @@ const Login = () => { } finally { setLoading(false); } - }, [email, password, dispatch, navigate]); + }, [email, password, dispatch, navigate, searchParams]); return (
diff --git a/src/routes/AppRouter.jsx b/src/routes/AppRouter.jsx index 4402e15..ad53cb2 100644 --- a/src/routes/AppRouter.jsx +++ b/src/routes/AppRouter.jsx @@ -7,6 +7,7 @@ import Spinner from '../components/common/Spinner'; import NotFound from '../pages/NotFound'; import ErrorTest from '../components/common/ErrorTest'; import AdminRoute from './AdminRoute'; +import ProtectedRoute from './ProtectedRoute'; // Auth pages import Login from '../pages/Login'; @@ -40,7 +41,11 @@ const AppRouter = () => { } /> } /> } /> - } /> + + + + } /> } /> @@ -51,7 +56,11 @@ const AppRouter = () => { } /> {/* App pages */} - } /> + + + + } /> diff --git a/src/routes/ProtectedRoute.jsx b/src/routes/ProtectedRoute.jsx new file mode 100644 index 0000000..ec51008 --- /dev/null +++ b/src/routes/ProtectedRoute.jsx @@ -0,0 +1,27 @@ +import { Navigate, useLocation } from 'react-router-dom'; +import { useSelector } from 'react-redux'; +import { selectIsAuthenticated } from '../features/auth/authSelectors'; + +/** + * ProtectedRoute - A higher-order route component that restricts access to authenticated users + * Redirects unauthenticated users to /login?redirect=/original-path + * + * @param {Object} props - Component props + * @param {React.ReactNode} props.children - The component to render if user is authenticated + * @returns {React.ReactElement} Either the children or a redirect to login + */ +const ProtectedRoute = ({ children }) => { + const isAuthenticated = useSelector(selectIsAuthenticated); + const location = useLocation(); + + // If user is not authenticated, redirect to login with redirect query param + if (!isAuthenticated) { + const redirectPath = encodeURIComponent(location.pathname + location.search); + return ; + } + + // User is authenticated, render the protected component + return children; +}; + +export default ProtectedRoute;