Frontend Routing
Relevant source files
The following files were used as context for generating this wiki page:The frontend routing system for the AirZen application is built using the react-router-dom library. It manages navigation and access control by defining a clear structure of public, protected user, and protected admin routes. The system leverages nested routing with shared layouts to maintain a consistent user interface across different sections of the application.
The core of the routing logic is centralized in App.js, which defines all available paths and the components they render. Access to protected areas is controlled by wrapper components like ProtectedRoute and RequireAdmin, which enforce authentication and authorization rules, redirecting unauthorized users as needed.
Core Setup
The application's routing capabilities are initialized in the main entry point file, frontend/src/index.js. The entire App component, which contains the route definitions, is wrapped with the <BrowserRouter> component. This provides the routing context to all child components, enabling them to use hooks like useNavigate and components like <Link> and <NavLink>.
Sources: frontend/src/index.js:9-19
// frontend/src/index.js:15
root.render(
<React.StrictMode>
<BrowserRouter>
<AuthProvider>
<ThemeProvider>
<App />
</ThemeProvider>
</AuthProvider>
</BrowserRouter>
</React.StrictMode>
);
Sources: frontend/src/index.js:15-25
Routing Architecture
The main routing configuration is defined within the App component. It uses the <Routes> and <Route> components from react-router-dom to map URL paths to specific page components. The architecture is divided into three main categories: Public Routes, Protected User Routes, and Protected Admin Routes.
Sources: frontend/src/App.js:28-60
This diagram illustrates the high-level routing structure and access control flow.
Sources: frontend/src/App.js:28-60
Public Routes
These routes are accessible to all users, including unauthenticated visitors. They are defined directly under the <Routes> component.
| Path | Component | Description |
|---|---|---|
/ | <Public_page /> | The main landing page for the application. |
/signin | <SignIn /> | The user sign-in page. |
/register | <Register /> | The user registration page. |
Sources: frontend/src/App.js:30-32
Protected User Routes
These routes are only accessible to authenticated users. They are grouped within a parent <Route> element that uses element={<ProtectedRoute />}. This ProtectedRoute component is responsible for checking the user's authentication status. If the user is not logged in, they will be redirected. The nested routes share a common UI structure provided by the <Layout /> component, which renders a sidebar and navbar around the page content via an <Outlet />.
| Path | Component | Description |
|---|---|---|
/dashboard | <Dashboard /> | The main dashboard for logged-in users. |
/air-quality | <AirQualityIndexPage /> | Page to view air quality index data. |
/threshold | <ThresholdePage /> | Page for configuring alert thresholds. |
/history | <History /> | Page to view historical sensor data. |
/settings | <Setting /> | User settings page. |
Sources: frontend/src/App.js:35-43
Protected Admin Routes
These routes are restricted to users with an 'admin' role. Access is controlled by the <RequireAdmin /> component, which acts as a role-based guard. Similar to user routes, admin routes are nested within the <LayoutAdmin /> component to provide a consistent administrative interface.
| Path | Component | Description |
|---|---|---|
/admin/overview | <AdminOverview /> | The main overview dashboard for admins. |
/admin/users | <UserManagerment /> | Page for managing users. |
/admin/devices | <DeviceManagerment /> | Page for managing IoT devices. |
/admin/request | <RequestSupport /> | Page for handling user support requests. |
/admin/notification | <NotificationPage /> | Page for managing system notifications. |
/admin/setting | <AdminSetting /> | Admin-specific settings page. |
Sources: frontend/src/App.js:46-55
Fallback Route
A fallback route is defined to handle any paths that do not match the defined routes. It uses <Navigate to="/" replace /> to redirect the user back to the home page.
// frontend/src/App.js:58
<Route path="*" element={<Navigate to="/" replace />} />
Sources: frontend/src/App.js:58
Layouts and Nested Routing
The application makes effective use of nested routing to create shared layouts for different sections. The <Layout /> and <LayoutAdmin /> components define the common structure (e.g., sidebar, navbar) and use the <Outlet /> component from react-router-dom to render the specific child route's component.
This approach avoids duplicating layout code on every page and centralizes the UI structure for user and admin sections.
The following diagram shows the component structure for a protected route.
Navigation
Navigation between pages is handled in two primary ways: declarative navigation using link components and programmatic navigation using a hook.
Declarative Navigation (<NavLink>)
The admin sidebar uses the <NavLink> component to create navigation links. <NavLink> is aware of the current route and can apply styling to the active link, which is used to highlight the user's current location in the menu.
Sources: frontend/src/components/common/SidebarAdmin.js:92-106
// frontend/src/components/common/SidebarAdmin.js:92
<NavLink
key={item.key}
to={item.path}
className={({ isActive }) =>
`flex items-center gap-3 relative z-10 select-none ... ${
isActive
? "text-emerald-700 dark:text-emerald-200"
: "text-gray-500"
}`
}
>
{/* ... icon and label */}
</NavLink>
Sources: frontend/src/components/common/SidebarAdmin.js:92-106
Programmatic Navigation (useNavigate)
In some cases, navigation is triggered by an event, such as a button click. The useNavigate hook is used for this purpose. For example, on the public landing page, clicking the "Bắt đầu" button programmatically navigates the user to the /signin page.
// frontend/src/pages/Public_page.js:15
const navigate = useNavigate();
// ...
// frontend/src/pages/Public_page.js:176
<button
onClick={() => navigate("/signin")}
className="..."
type="button"
>
Bắt đầu
</button>
Sources: frontend/src/pages/Public_page.js:15, frontend/src/pages/Public_page.js:176-182