Protect the react routes with two different layouts childrens - reactjs

I am protecting the routes and making sure the if no route found or if the user does not loggedin, then redirects the user to login page. I have tried a lot solutions but nothing work for me.I have tried with the variable but I got nothing, the user does not navigate to login screen if const a !== 'admin',
All I wanted if const a === 'admin' then navigate to routes and if no route found then navigate to '/' path and if const a !== 'admin' then navigate to '/login'
App.js code
enter code hereimport { useSelector } from 'react-redux';
import { ThemeProvider } from '#mui/material/styles';
import { CssBaseline, StyledEngineProvider } from '#mui/material';
// routing
// import Routes from 'routes';
// defaultTheme
import themes from 'themes';
// project imports
import NavigationScroll from 'layout/NavigationScroll';
// Alert toastify
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { Navigate } from 'react-router';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import MainLayout from './layout/MainLayout';
import AuthLayout from './layout/MinimalLayout';
import DashboardDefault from './views/dashboard/Default';
import Orders from './views/pages/orders/orders';
import MenuPage from './views/pages/Menu/Menu';
import PromoCodesPage from './views/pages/promocodes/PromoCodes';
import LoginPage from './views/pages/authentication/authentication3/Login3';
// ==============================|| APP ||============================== //
const App = () => {
const customization = useSelector((state) => state.customization);
const a = 'admin';
return (
<StyledEngineProvider injectFirst>
<ToastContainer />
<ThemeProvider theme={themes(customization)}>
<CssBaseline />
<NavigationScroll>
<Routes>
{a === 'admin' ? (
<Route path="/" element={<MainLayout />}>
<Route path="/" element={<DashboardDefault />} />
<Route path="/dashboard/default" element={<DashboardDefault />} />
<Route path="/orders" element={<Orders />} />
<Route path="/menu" element={<MenuPage />} />
<Route path="/promocodes" element={<PromoCodesPage />} />
</Route>
) : (
<Route path="/" element={<AuthLayout />}>
<Route path="/login" element={<LoginPage />} />
</Route>
)}
</Routes>
</NavigationScroll>
</ThemeProvider>
</StyledEngineProvider>
);
};
export default App;

Related

How do I add a react landing page to a react app?

I have coded a landing page in react, and in a separate project a react/typescript app. How would I go about setting my website up so that when there's no user auth, the landing page and all its features show, and when logged in change the landing page to the actual app [e.g. twitter]. I realise that in my app project folder, I will need to change a few things, but I'm not sure what exactly.
React landing page app.jsx:
import React, { useEffect, useState } from 'react';
import {
Routes,
Route,
useLocation
} from 'react-router-dom';
import 'aos/dist/aos.css';
import './css/style.css';
import AOS from 'aos';
import Home from './pages/Home';
import SignIn from './pages/SignIn';
import SignUp from './pages/SignUp';
import ResetPassword from './pages/ResetPassword';
import LearnMore from './pages/LearnMore';
import AboutUs from './pages/AboutUs';
import ComingSoon from './pages/ComingSoon';
import RecosiaPay from './pages/RecosiaPay';
import RecosiaBank from './pages/RecosiaBank';
import Guides from './pages/Guides';
import PrivacyPolicy from './pages/PrivacyPolicy';
import Support from './pages/Support';
import Pitchdeck from './pages/PitchDeck';
function App() {
const location = useLocation();
useEffect(() => {
AOS.init({
once: true,
disable: 'phone',
duration: 700,
easing: 'ease-out-cubic',
});
});
useEffect(() => {
document.querySelector('html').style.scrollBehavior = 'auto'
window.scroll({ top: 0 })
document.querySelector('html').style.scrollBehavior = ''
}, [location.pathname]); // triggered on route change
return (
<>
<Routes>
<Route exact path="/" element={<Home />} />
<Route path="/signin" element={<SignIn />} />
<Route path="/signup" element={<SignUp />} />
<Route path="/guides" element={<Guides />} />
<Route path="/support" element={<Support />} />
<Route path="/pitch-deck" element={<Pitchdeck />} />
<Route path="/privacy-policy" element={<PrivacyPolicy />} />
<Route path="/recosia-pay" element={<RecosiaPay />} />
<Route path="/recosia-bank" element={<RecosiaBank />} />
<Route path="/learn-more" element={<LearnMore />} />
<Route path="/coming-soon" element={<ComingSoon />} />
<Route path="/about-us" element={<AboutUs />} />
<Route path="/reset-password" element={<ResetPassword />} />
</Routes>
</>
);
}
export default App;
and React Typescript [actual application] App.jsx code:
import type { AppProps } from 'next/app'
import { ChakraProvider } from '#chakra-ui/react'
import { theme } from '../chakra/theme';
import Layout from "../components/Layout/Layout";
import { RecoilRoot } from 'recoil';
function MyApp({ Component, pageProps }: AppProps) {
return (
<RecoilRoot>
<ChakraProvider theme={theme}>
<Layout>
<Component {...pageProps} />
</Layout>
</ChakraProvider>
</RecoilRoot>
);
}
export default MyApp;
I would set up some form of a state manager using redux, or just the context api from react. Once you have this, you can separate your routes into an <AuthenticatedApp/> and an <UnauthenticatedApp/>. Based on the authentication status put on state, you can have a memoized value listening for changes to that authentication status. When changed, you can switch between which set of routes are displayed to the user!
You can either use an authentication library like auth-0, or
You can use a state manager (useState, useContext, redux, etc.) to track whether the user has logged in or not, and show the route that you want.
This is a good pattern to start with:
https://blog.logrocket.com/complete-guide-authentication-with-react-router-v6/

Error: [AdminRoute] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>

I want authenticated routes if user is not logged in the page should not be accessible like if someone enters in the url localhost.../admin/dashboard he should not be able to navigate instead he should be taken to signin page if not logged in.
I'm using react-router v6 and creating private routes for my application.
AdminRoute.js File Code is below
import React from "react";
import { Route, Navigate} from 'react-router-dom';
import { isAuthenticated } from "../helper/auth";
//props component is assigned to Component
//...rest spreading props property but reassigning it to a variable called rest
const AdminRoute = ({ component: Component, ...rest }) => {
return (
<Route
{...rest}
render={(props) =>
isAuthenticated() && isAuthenticated().role === 1 ? (
<Component {...props} />
) : (
<Navigate to = '/signin' />
)
}
/>
)
};
export default AdminRoute;
App.js File Code is below
import React from 'react';
import {BrowserRouter, Route, Routes} from 'react-router-dom';
import Header from './Header';
import Home from './Home';
import Signup from './Signup';
import Signin from './Signin';
import ForgotPassword from './forgot-password';
import UserDashboard from './UserDashboard';
import AdminDashboard from './AdminDashboard';
import ShowroomDashboard from './ShowroomDashboard';
import AdminRoute from './AdminRoute';
import NotFound from './NotFound';
const App = () => (<BrowserRouter>
<Header />
<main>
<Routes>
<Route exact path='/' element={<Home />} />
<Route exact path='/signup' element={<Signup />} />
<Route exact path='/signin' element={<Signin />} />
<Route exact path='/forgotpassword' element={<ForgotPassword />} />
<Route exact path='/user/dashboard' element={<UserDashboard />} />
<AdminRoute exact path='/admin/dashboard' element={<AdminDashboard />} />
<Route exact path='/showroom/dashboard' element={<ShowroomDashboard />} />
<Route exact path = '*' element={<NotFound />} />
</Routes>
</main>
</BrowserRouter>
);
export default App;
react-router-dom no longer supports custom route components, preferring now component wrappers that handle the auth logic and render either the children prop or an Outlet for nested routes, or the redirect.
Wrap a single "Route" component:
import React from "react";
import { Navigate } from 'react-router-dom';
import { isAuthenticated } from "../helper/auth";
const AdminRoute = ({ children }) => {
return isAuthenticated()?.role === 1
? children
: <Navigate to='/signin' replace />;
};
...
<Route
path='/admin/dashboard'
element={(
<AuthRoute>
<AdminDashboard />
</AuthRoute>
)}
/>
Wrap nested Route components:
import React from "react";
import { Navigate, Outlet } from 'react-router-dom';
import { isAuthenticated } from "../helper/auth";
const AdminWrapper = () => {
return isAuthenticated()?.role === 1
? <Outlet />
: <Navigate to='/signin' replace />;
};
...
<Route path='/admin/dashboard/*' element={<AdminWrapper />}>
<Route index element={<AdminDashboard />} />
... any other '/admin/dashboard/*' routes ...
</Route>

React Router Dom how to redirect to Other App.js route when you are in any subRoute of any route [duplicate]

This question already has answers here:
React Router works only after refreshing the page
(5 answers)
Closed 1 year ago.
I'm new to react & react router dom v5, also my english is bad. Thank you in advance for helping me.
my problem:
I have 2 Main Routes in my App.js route
import { Suspense } from 'react';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom'
/* Pges */
import AdminContainer from './Pages/Admin/AdminContainer';
import PublicContainer from './Pages/Public/PublicContainer';
import NotFound from './Pages/NotFound'
import AuthContainer from './Pages/Auth/AuthContainer';
/* Protected Route */
/* Helpers */
function App() {
console.log("APP")
return (
<Suspense fallback={(<p>Loading</p>)}>
<Router>
<Switch>
<Route path="/auth" component={AuthContainer} />
<Route path="/admin" component={AdminContainer} />
<Route path="/*" component={PublicContainer} />
<Route path="*" component={NotFound} />
</Switch>
</Router>
</Suspense>
)
}
export default App;
the authcontainer have 2 sub routes
"/signin"
"/signup"
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
withRouter
} from "react-router-dom";
// PAGES
import Signin from "../Auth/Signin";
import Signup from "../Auth/Signup";
const AuthContainer = () => {
console.log("AUTH")
return (
<div>
<Router>
<Switch>
<Route exact path="/auth" component={Signin}/>
<Route exact path="/auth/signin" component={Signin}/>
<Route exact path="/auth/signup" component={Signup}/>
</Switch>
</Router>
</div>
);
};
export default withRouter(AuthContainer);
then the my publiccontainer have 3 sub routes
"/"
"/product"
"/mycart"
/* Dependencies */
import { Route, Switch, BrowserRouter as Router } from 'react-router-dom'
/* Components */
import Header from "../../Components/Header"
import Products from "./Products"
import Home from "./Home"
import UserProfile from "../User/AccountProfile"
import MyCart from '../Public/MyCart'
const PublicContainer = () => {
console.log("PUBLIC")
return (
<div>
<Router>
<Header />
<Switch>
<Route exact path='/' render={(props) => <Home />} />
<Route exact path='/products' render={(props) => <Products />} />
<Route exact path='/mycart' render={(props) => <MyCart isAuth={false} />} />
</Switch>
</Router>
</div>
)
}
export default PublicContainer
the my cart component will only render if isAuth is true, else it will redirect to "/auth/signin"
import React from 'react'
import { Redirect } from 'react-router'
const MyCart = ({isAuth}) => {
if(!isAuth)
return (<Redirect from='*' to='/auth/signin'></Redirect>)
return (
<div>
my cart
</div>
)
}
export default MyCart
The problem is, its trying to redirect to "/auth/signin" but it is still in the "/" page
When i hit reload it finally redirect to "/auth/signin"
How can i fix this issue, I really appreciate your help
UPDATE
this is overview of my planned routes
By the way i think when the mycart isAuth is false then it tries to Link to /auth/signin which causes the link in the top url to correctly point to auth signin, but after that it only checks the subroutes of the publiccontainer instead of checking the app.js routes
But when i reload it, it start searching the correct route from the app.js routes which return the expected route & page which is the sign in
I read a almost similar question in terms of only rendering the correct path when hitting refresh/reload
here React Router works only after refreshing the page
The problem was i'm wrapping the sub routes with a new router, so i tried removing the Router jsx that is wrapping the Switch> & other subroutes in both AuthContainer.js & PublicContainer.js
this is the updated AuthContainer.js
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
withRouter
} from "react-router-dom";
// PAGES
import Signin from "../Auth/Signin";
import Signup from "../Auth/Signup";
const AuthContainer = () => {
console.log("AUTH")
return (
<div>
<Switch>
<Route exact path="/auth/signin" component={Signin}/>
<Route exact path="/auth/signup" component={Signup}/>
<Route exact path="/auth" component={Signin}/>
</Switch>
</div>
);
};
export default withRouter(AuthContainer);
And this is the PublicContainer.js
/* Dependencies */
import { Route, Switch } from 'react-router-dom'
/* Components */
import Header from "../../Components/Header"
import Products from "./Products"
import Home from "./Home"
import UserProfile from "../User/AccountProfile"
import MyCart from '../Public/MyCart'
/* Protected */
const PublicContainer = ({toAuth}) => {
console.log("PUBLIC")
return (
<div>
<Header />
<Switch>
<Route exact path='/products' render={(props) => <Products />} />
<Route exact path='/profile' render={(props) => <UserProfile />} />
<Route exact path='/mycart' render={(props) => <MyCart />} />
<Route exact path='/' render={(props) => <Home />} />
</Switch>
</div>
)
}
export default PublicContainer

Route guard while using ionic + react

I want to redirect the unauthenticated user to /login. I have a property in my context called loggedIn, when it is false I want to make a redirect to HomePage i.e "/".
I just got confused due to the route structure. I'm seeing something like a protected route everywhere.
import React, { useContext, useEffect } from "react";
import { Redirect, Route } from "react-router-dom";
import { IonApp, IonRouterOutlet, IonSplitPane } from "#ionic/react";
import { IonReactRouter } from "#ionic/react-router";
import { setupConfig } from "#ionic/react";
import { Plugins, Capacitor } from "#capacitor/core";
import { useHistory } from "react-router-dom";
import Home from "./pages/Home/Home";
/* Core CSS required for Ionic components to work properly */
import "#ionic/react/css/core.css";
/* Basic CSS for apps built with Ionic */
import "#ionic/react/css/normalize.css";
import "#ionic/react/css/structure.css";
import "#ionic/react/css/typography.css";
/* Optional CSS utils that can be commented out */
import "#ionic/react/css/padding.css";
import "#ionic/react/css/float-elements.css";
import "#ionic/react/css/text-alignment.css";
import "#ionic/react/css/text-transformation.css";
import "#ionic/react/css/flex-utils.css";
import "#ionic/react/css/display.css";
import "../src/utils/spacing.css";
/* Theme variables */
import "./theme/variables.css";
/* Components */
import Dashboard from "./pages/Dashboard/Dashboard";
import SideMenu from "./components/SideMenu/SideMenu";
import LoginPage from "./pages/Login/Login";
import SignupPage from "./pages/Signup/Signup";
import Create from "./pages/Create/Create";
import Edit from "./pages/Edit/Edit";
import { AuthContext, AuthProvider } from "./providers/context/AuthContext";
const App: React.FC = () => {
const history = useHistory();
return (
<IonApp>
<AuthProvider>
<IonReactRouter>
<IonSplitPane contentId="main">
<SideMenu />
<IonRouterOutlet id="main">
<Route path="/dashboard/:name" component={Dashboard} exact />
<Route path="/dashboard/Edit/:id" component={Edit} exact />
// if !user navigate to login component
<Route path="/create" component={Create} exact />
<Route path="/signup" component={SignupPage} exact />
<Route path="/" component={Home} exact />
<Redirect from="/dashboard" to="/dashboard/Home" exact />
</IonRouterOutlet>
</IonSplitPane>
</IonReactRouter>
</AuthProvider>
</IonApp>
);
};
export default App;
Might be useful for anyone: is solved it by using the Private Route and pubic Route trick
I Created a component called PrivateRoute.tsx and added the following:
import React, { useContext } from "react";
import { Route, Redirect } from "react-router-dom";
import { EnrolleeContext } from "../providers/context/EnrolleeContext";
const PrivateRoute = ({ component: Component, ...rest }: any) => {
const { loggedIn } = useContext(EnrolleeContext);
return (
// Show the component only when the user is logged in
// Otherwise, redirect the user to /signin page
<Route
{...rest}
render={(props) =>
loggedIn ? <Component {...props} /> : <Redirect to="/" />
}
/>
);
};
export default PrivateRoute;
Also created a Public Route, added restricted to be able to restrict Components if restricted == true, meaning the Route is Private, if false, otherwise.
import React, { useContext } from "react";
import { Route, Redirect } from "react-router-dom";
import { EnrolleeContext } from "../providers/context/EnrolleeContext";
const PublicRoute = ({ component: Component, restricted, ...rest }: any) => {
const { loggedIn } = useContext(EnrolleeContext);
return (
// restricted = false meaning public route
// restricted = true meaning restricted route
<Route
{...rest}
render={(props) =>
loggedIn && restricted ? (
<Redirect to="/dashboard/Home" />
) : (
<Component {...props} />
)
}
/>
);
};
export default PublicRoute;
Updated App.tsx
<PublicRoute restricted={false} component={Home} path="/" exact />
<PublicRoute
restricted={true}
component={LoginPage}
path="/login"
exact
/>
<PrivateRoute
component={Dashboard}
path="/dashboard/:name"
exact
/>
<PrivateRoute component={Create} path="/create" exact />
<PublicRoute
restricted={false}
component={ForgotPassword}
path="/forgot-password"
exact
/>
Other Routes like forgot password is open to the public`, while Create is Private, so it is at your own discretion.

React V6 route guarding and routing within component

Im trying to use React Routing V6 for my project.
Currently im struggeling to make the authentication and routing itself to work.
the idea of my code is:
Not authenticated user:
redirect to /login with my login component. (only login component)
Authenticated user:
Load the gameComponent component, and the rest of links inside of gamecomponent, will load inside gameComponents div class named middleContentHolder
examples:
authenticated user:
visits url /crime -> loads gamecomponent, and within gamecomponent it loads the crime component.
visits url /test -> loads gamecomponent , and within gamecomponent it loads the SideBarRight component.
not authenticated user:
vitits url /crime -> not authenticated -> redirects to /login -> loads loginmodule only.
please note that in gamecomponent component, i do have links that will load within gamecomponent.
app.js will either load the gamecomponent, or redirect user to login if not auth.
app.js:
import React from 'react';
import logo from './logo.svg';
import './App.css';
import GameComponent from './gameComponent.jsx';
import { BrowserRouter as Router } from 'react-router-dom';
import { Routes, Route, Navigate, Outlet } from 'react-router-dom';
import Crime from './components/game/crime.jsx';
import PrivateRoute from './PrivateRoute';
import Login from './components/login/login.jsx';
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<GameComponent />}>
<PrivateRoute isAuth={true} path="crime" component={Crime} redirectTo='/login'/>
</Route>
</Routes>
</Router>
);
}
export default App;
Gamecomponent:
import React, {Component} from 'react';
//import Component from 'react-dom';
import SideBarRight from './components/game/sideBarRight.jsx';
import SideBarLeft from './components/game/sideBarLeft.jsx';
import Crime from './components/game/crime.jsx';
import Login from './components/login/login.jsx';
import './gameComponent.css';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import { BrowserRouter} from "react-router-dom";
class GameComponent extends Component{
constructor() {
super();
this.state = {
userData: {
user: {cash:0, bank:0, weapon:'', username: 'test', locationname: 'Bankok',
defence: 0},
rankbar: {rankpercent: 50, rank: 'Mafia'},
}
}
}
render() {
return (
<div className="main">
<div className="sidebar left">
<SideBarLeft/>
</div>
<div className="middleContentHolder">
<Route path="/" element={<Crime />} />
<Route path="/test" element={<Crime />} />
<Route path="/crime" element={<Crime />} />
<Route path="/test" element={<SideBarRight UserData={this.state.userData} />} />
<div className="col-8">
<div className="content">
<div className="header"><span>Test...</span></div>
</div>
</div>
</div>
<div className="sidebar right">
<SideBarRight UserData={this.state.userData}/>
</div>
</div>
);
}
}
export default GameComponent;
PrivateRoute:(auth is just a dummy atm)
import React from 'react';
import PropTypes from 'prop-types';
import { Route, Navigate } from 'react-router-dom';
import { useNavigate } from "react-router-dom";
import Login from './components/login/login.jsx';
import GameComponent from './gameComponent.jsx';
const PrivateRoute = ({ component: Component, redirectTo, isAuth, path, ...props }) => {
isAuth = false;
if(!isAuth) {
return <Navigate to={redirectTo} />;
}
return <Route path={path} element={<Component />} />
};
export default PrivateRoute;
update:
orginal auth was:in privateroute:
isAuth = isAuth;
one example of non-working code that would show what i want:
<Route path="/login" element={}>
<PrivateRoute isAuth={true} path="/" component={GameComponent} redirectTo='/login'>
rest of routes exist in gamecomponent..
</PrivateRoute>
If you only want GameComponent to load if use is authenticated, you will need to change your App component like this:
function App() {
return (
<Router>
<Routes>
<Route path="/login" element={<LoginComponent />} />
<PrivateRoute isAuth={true} path="/" component={GameComponent} redirectTo='/login'/>
</Routes>
</Router>
);
}
Here we are essentially putting a switch so that we can navigate to /login when there is no authentication. <Routes> is vital here, because it will only render the component that matches the exact path.
With the official release of React Router V6, the other answer is no longer valid. It will throw an error since <PrivateRoute /> isn't a <Route />.
The proper way to do it is to refactor your <PrivateRoute /> component like so...
import { Navigate, useLocation } from "react-router-dom"
const PrivateRoute = (props: { children: React.ReactNode }): JSX.Element => {
const { children } = props
// Up to you specific app to decide how to get this value
const isLoggedIn: boolean = localStorage.getItem('logged_user') !== null;
const location = useLocation()
return isLoggedIn ? (
<>{children}</>
) : (
<Navigate
replace={true}
to="/login"
state={{ from: `${location.pathname}${location.search}` }}
/>
)
}
Then whichever file you setup your routes in, you would do...
<Routes>
<Route path="/PRIVATE" element={<PrivateRoute> <PrivatePage /> </PrivateRoute>}/>
<Route path="/profile" element={<PrivateRoute> <ProfilePage /> </PrivateRoute>}/>
<Route path="/login" element={<LoginPage />}/>
<Route path="/" element={<HomePage />}/>
</Routes>
This is the proper way of doing it in V6 since only a <Route /> can be nested in a <Routes />. Then your authenticated logic gets moved into the element prop.
As an added bonus, the state={{ from: `${location.pathname}${location.search}` }} in PrivateRoute allows you to get the URL of the page they tried to enter, but was denied. This is passed to your login page, where you can redirect them back to the URL after they authenticate.
Solution for newer version
Create custom middleware <AuthGuard> and use as wrapper
<PrivateRoute> not vaild for newer version as child of <Routes>
Error "A <Route> is only ever to be used as the child of <Routes> element"
App.js
import React from 'react'
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import AuthGuard from "./Routes/AuthGuard";
function App() {
return (
<div className='App'>
<Router>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/contact' element={<Contact />} />
<Route path='/guest-page' element={<AuthGuard isGuest={true}><h1>Guest Page</h1></AuthGuard>} />
<Route path='/protected-page' element={<AuthGuard requireToken={true}><h1>ProtectedPage</h1></AuthGuard>} />
</Routes>
</Router>
</div>
);
}
export default App;
AuthGuard.js
import { Route, useNavigate } from "react-router-dom";
import { useLayoutEffect } from "react";
const ProtectedRoute = ({requireToken, guest, children, ...rest}) => {
console.log(requireToken, guest, children, rest);
const navigate = useNavigate();
const hasToken = false;
let hasAccess = (!requireToken || (requireToken && hasToken));
let navigateTo = '/?login-rquired=true';
if(guest) {
hasAccess = !hasToken;
navigateTo = '/?guest=true';
console.log("Guest > hasAccess: " + hasAccess)
}
if(requireToken){
console.log("requireToken", requireToken)
}
useLayoutEffect(()=>{
if (!hasAccess) {
console.log("Not allowed");
navigate(navigateTo);
}
},[])
return (
<>{ hasAccess ? children : "Login required" }</>
)
}
export default ProtectedRoute;

Resources