1

I am working on migrating my app to React Router v6. I can't believe how many breaking changes they introduced with that! Hope they never do that again!

So I need to have some pages of the app private, that we are just authenticating with a basic password. I have followed the tutorial here: https://blog.logrocket.com/complete-guide-authentication-with-react-router-v6/ It all made sense and worked well. But now I'm trying to figure out how to route the user to the original requested page after they are logged in. I can't figure out where or how to get the original requested path. I did find this other SO question: React Router - PrivateRoute, redirect to original destination after login but for some reason, I do not have that data in my props.

Here is my useAuth hook where the issue lies:

import { createContext, useContext, useMemo } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { useLocalStorage } from './useLocalStorage';
import { authenticateUser } from '../utils/APIFunctions';

const AuthContext = createContext(undefined);

export const AuthProvider = ({ children }) => {
    // I did try (props) instead of ({children}), but there
    // is only one object called children in props
    console.log({ props });
    const [token, setToken] = useLocalStorage('token', null);
    const navigate = useNavigate();
    let location = useLocation();

    const login = async (data) => {
        const password = data.password;
        // check this password in the DB
        let error = '';
        authenticateUser(password).then((res) => {
            console.log({ res });
            console.log({ location });
            if (res?.status === 200 && res?.data[0]?.auth_level > 0) {
                // this is a valid password
                const time = Date.now();
                // setToken({ token: password + '-' + time });
                navigate(??? // this is where I need to put something so it knows where to send the user back to, if i only had one protected route, i could hardcode the path);
            } else {
                if (res.data.name === 'ConnectionError') {
                    error = 'Unable to connect to database.';
                } else if (res?.data?.ReturnValue === 0) {
                } else {
                    error = 'Error logging into Scheduler.';
                }
            }
        });

        //navigate('/baglines', { replace: true });
    };

    const logout = () => {
        setToken(null);
        navigate('/', { replace: true });
    };

    const value = useMemo(
        () => ({
            token,
            login,
            logout,
        }),
        [token]
    );

    return (
        <AuthContext.Provider value={value}>
            {children}
        </AuthContext.Provider>
    );
};

export const useAuth = () => {
    return useContext(AuthContext);
};

And here is my ProtectedRoute where useAuth gets used:

import { Navigate } from 'react-router-dom';
import { useAuth } from '../../hooks/useAuth';

export const ProtectedRoute = ({ children, ...rest }) => {
    const { token } = useAuth();
    // I also tried getting (props) here instead of ({children})
    // and once again only one object of 'children'
    let pathname = rest; // .location.pathname;

    console.log({ pathname });
    console.log({ token });
    if (!token) {
        // user is not authenticated
        return <Navigate to={'/login'} />;
    }
    return children;
};

And lastly, this is how I am implementing the ProtectedRoute:

    <Routes>
                <Route path={'/'} element={<LandingPage />} />
                <Route path={'/login'} element={<Login />} />
                <Route
                    path={'/baglines'}
                    element={
                        <ProtectedRoute>
                            <Scheduling
                            ...

Let me know if any more code is needed from me.

dmikester1
  • 1,374
  • 11
  • 55
  • 113

0 Answers0