refactor(web): add Redux state management and centralised routing
- Replace inline BrowserRouter with createBrowserRouter and lazy-loaded pages
- Add Redux store with auth-slice (token management) and redux-persist
- Create RequireAuth guard using Redux state via isAuthenticated selector
- Wire Layout logout to dispatch setToken("") clearing persisted auth
- Add ErrorPage component for route error handling
- Add EmptyLayout for unauthenticated pages
- Add VITE_REDUX_STORAGE env var for storage selection
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import type { ComponentType, ReactNode } from "react"
|
||||
import { createBrowserRouter, Navigate } from "react-router-dom"
|
||||
import ErrorPage from "@/components/ErrorPage"
|
||||
import Layout from "@/components/Layout"
|
||||
import EmptyLayout from "@/components/EmptyLayout"
|
||||
import { isAuthenticated } from "@/store/auth-slice"
|
||||
import { useAppSelector } from "@/store"
|
||||
|
||||
function lazy<T extends { default: ComponentType<unknown> }>(importer: () => Promise<T>) {
|
||||
return async () => {
|
||||
const module = await importer()
|
||||
return { Component: module.default }
|
||||
}
|
||||
}
|
||||
|
||||
const hydrateFallbackElement = <div className="px-4 py-6 text-neutral-500">Loading...</div>
|
||||
|
||||
function RequireAuth({ children }: { children: ReactNode }) {
|
||||
const authenticated = useAppSelector(isAuthenticated)
|
||||
if (!authenticated) return <Navigate to="/login" replace />
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
const router = createBrowserRouter(
|
||||
[
|
||||
{
|
||||
path: "/",
|
||||
element: <Navigate to="/dashboard" replace />,
|
||||
},
|
||||
{
|
||||
element: (
|
||||
<RequireAuth>
|
||||
<Layout />
|
||||
</RequireAuth>
|
||||
),
|
||||
hydrateFallbackElement,
|
||||
errorElement: <ErrorPage />,
|
||||
children: [
|
||||
{
|
||||
path: "dashboard",
|
||||
lazy: lazy(() => import("@/pages/Dashboard")),
|
||||
},
|
||||
{
|
||||
path: "artefacts",
|
||||
lazy: lazy(() => import("@/pages/Artefacts")),
|
||||
},
|
||||
{
|
||||
path: "deployments",
|
||||
lazy: lazy(() => import("@/pages/Deployments")),
|
||||
},
|
||||
{
|
||||
path: "users",
|
||||
lazy: lazy(() => import("@/pages/Users")),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
element: <EmptyLayout />,
|
||||
hydrateFallbackElement,
|
||||
errorElement: <ErrorPage />,
|
||||
children: [
|
||||
{
|
||||
path: "login",
|
||||
lazy: lazy(() => import("@/pages/Login")),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
{ basename: "/" }
|
||||
)
|
||||
|
||||
export default router
|
||||
Reference in New Issue
Block a user