I would like to check if my cms is installed (with a api call to my backend).
I can fetch the value, I can see the "ok" value into console, but I'm not redirected to /login as expected.
I suspect const content = useRoutes(routes(isInstalled, isLogged));
is not updated, isInstalled state, when is updated, is not send with its new value to routes.js.
App.js:
function App() {
const [isLogged, setIsLogged] = useState<boolean>(false);
const [isInstalled, setIsInstalled] = useState<boolean>(false);
const [client, setClient] = useState<any>();
const content = useRoutes(routes(isInstalled, isLogged));
const location = useLocation();
useEffect(() => {
const transport = createGrpcWebTransport({
baseUrl: `http://127.0.0.1:50051`,
});
const client = createPromiseClient(Lucle, transport);
setClient(client);
if (location.pathname == "/admin") {
check_if_installed(client)
.then(() => {
console.log("ok");
setIsInstalled(true)
})
.catch(() => {
console.log("NOK");
setIsInstalled(false)
});
}
}, []);
return (
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<GlobalStyles />
{content}
</ThemeProvider>
</StyledEngineProvider>
);
}
routes.js
const routes = (isInstalled: boolean, isLogged: boolean) => [
{ path: "/login", element: <Login /> },
{
path: "admin",
element: !isInstalled ? (
<Navigate to="/install" />
) : !isLogged ? (
<Navigate to="/login" />
) : (
<Dashboard />
),
children: [
{ path: "", element: <AdminIndex /> },
{ path: "editor", element: <OnlineEditor /> },
{ path: "tables", element: <Tables /> },
],
},
{
path: "/install",
element: <Install />,
},
];
How to update routes ?
Navigation to either of "/login"
or "/install"
only occurs when on the "/admin"
route, and since both isLogged
and isInstalled
start out initially false
, the UI is going to be navigated to either of "/login"
or "/install"
if starting from "/admin"
. Neither "/login"
or "/install"
check the state and navigate anywhere else.
You basically need to implement a route protection scheme.
Here's a basic example of route protection using your state and routes.
import { Navigate, Outlet } from "react-router-dom";
const AnonymousRoutes = ({ isLogged }: { isLogged: boolean }) => {
return isLogged ? <Navigate to="/admin" replace /> : <Outlet />;
};
const PrivateRoutes = ({ isLogged }: { isLogged: boolean }) => {
return isLogged ? <Outlet /> : <Navigate to="/login" replace />;
};
const InstalledRoutes = ({ isInstalled }: { isInstalled: boolean }) => {
return isInstalled ? <Outlet /> : <Navigate to="/install" replace />;
};
const UninstalledRoutes = ({ isInstalled }: { isInstalled: boolean }) => {
return isInstalled ? <Navigate to="/admin" replace /> : <Outlet />;
};
const routes = (isInstalled: boolean, isLogged: boolean) => [
{
element: <AnonymousRoutes isLogged={isLogged} />,
children: [{ path: "/login", element: <Login /> }]
},
{
element: <PrivateRoutes isLogged={isLogged} />,
children: [
{
element: <InstalledRoutes isInstalled={isInstalled} />,
children: [
{
path: "admin",
element: <Dashboard />,
children: [
{ index: true, element: <AdminIndex /> },
{ path: "editor", element: <OnlineEditor /> },
{ path: "tables", element: <Tables /> }
]
}
]
},
{
element: <UninstalledRoutes isInstalled={isInstalled} />,
children: [{ path: "/install", element: <Install /> }]
}
]
}
];
Now if while any of these routes are currently rendered and the "app state" changes, the access to that route will be re-evaluated and conditionally allow the Outlet
to be rendered and the "protected" content to be rendered or a redirect to a "safe route" is rendered. For example, if a user is unauthenticated and accesses a "ProtectedRoutes" route, they redirect to "/login"
, and vice-versa, if they are already authenticated and attempt to access "/login"
the UI will bounce them off that route back to "/admin"
.