How to add protected routes in react redux

As others already described, you had better to create a Protected Route to accomplish what you want. You simply redirect the user to the Login route if he/she is not logged in.

Here is my implementation: (codesandbox)

import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";

const ProtectedRoute = ({
  path,
  component: Component,
  render,
  loggedIn,
  ...rest
}) => {
  return (
    <Route
      path={path}
      {...rest}
      render={(props) => {
        if (loggedIn) {
          return Component ? <Component {...props} /> : render(props);
        }
        return (
          <Redirect
            to={{
              pathname: "/login",
              state: { from: props.location }
            }}
          />
        );
      }}
    />
  );
};

const mapStateToProps = (state) => {
  const { loggedIn } = state.auth;
  return {
    loggedIn
  };
};

export default connect(mapStateToProps)(ProtectedRoute);

You could simply define a custom ProtectedRoute component that'll be connected to redux state. In your case it should map state.auth.loggedIn and state.auth.user to props and perform a Redirect if those values are falsy:

import React from "react";
import { Route, Redirect } from "react-router-dom";
import PropTypes from "prop-types";


const ProtectedRoute = (props) => {
  const { redirectPath, component, user, loggedIn, ...routeProps} = props;
  const Component = component;
  const isAccessible = Boolean(user) && loggedIn;

  return (
    <Route
      {...routeProps}
      render={props => {
        if (isAccessible) return <Component {...props} />;
        return <Redirect to={{ pathname: redirectPath || "/Login" }} />;
      }}
    />
  );
};

ProtectedRoute.propTypes = {
  path: PropTypes.string.isRequired,
  redirectPath: PropTypes.string,
  component: PropTypes.oneOfType([
    PropTypes.shape({ render: PropTypes.func.isRequired }),
    PropTypes.func
  ]),
};

const mapStateToProps = (state) => {
  return { 
    loggedIn: state.auth.loggedIn, 
    user: state.auth.user 
  };
};

export default connect(mapStateToProps)(ProtectedRoute);

With this in place your MainRoutes won't need connect anymore:

const MainRoutes = props => {
  return (
    <Router history={history}>
      ...
      <Container maxWidth="md">
        <Switch>
          <Route exact path="/Login" component={Login} />
          <ProtectedRoute exact path="/Carousel" component={Carousel} />
          <ProtectedRoute exact path="/Stepper" component={Stepper} />
          <Route component={NotFound} />
        </Switch>
      </Container>
    </Router>
  );
}

export default MainRoutes;

Update:

If you want to keep auth state after page refresh you'll need to perform some extra setup of your redux store. The main idea is to subscribe on every action and put a fresh copy of state into localStorage or cookies and also to persist initialState from selected storage before your app boots up. Here is an example:

function getFromStorage(key) {
  try {
    return JSON.parse(window.localStorage.getItem(key)) || {};
  } catch (err) {
    return {};
  }
}

const initialState = getFromStorage("APP_STATE");

const store = createStore(
  rootReducer,
  initialState, // should go after root reducer
  ...
);

store.subscribe(() => {
  window.localStorage.setItem("APP_STATE", JSON.stringify(store.getState()));
});

And here's the working sandbox (bootstrapped by SuleymanSah)