Routing and Permission Control
Fireact.dev applications utilize react-router-dom
for declarative routing, allowing you to define different paths and render specific components or layouts based on the URL. A key aspect of this routing is the integrated permission control, which restricts access to certain routes based on user authentication status and subscription permissions.
Defining Routing Paths (app.config.json
):
In Fireact.dev, routing paths are centrally defined in the app.config.json
file, specifically within the pages
object. This approach allows for easy management and modification of your application’s URLs without needing to change code directly in your React components.
Example (test-app/src/config/app.config.json
snippet):
{
"name": "Fireact",
"pages": {
"home": "/",
"dashboard": "/dashboard",
"profile": "/profile",
"signIn": "/signin",
"signUp": "/signup",
"subscription": "/subscription/:id",
"users": "/subscription/:id/users",
"invite": "/subscription/:id/users/invite",
"settings": "/subscription/:id/settings",
"changePlan": "/subscription/:id/billing/change-plan"
// ... other page paths
},
"permissions": {
// ... permission definitions
},
"settings": {
// ... settings definitions
},
"emulators": {
// ... emulator configurations
}
}
- Each key in the
pages
object represents a logical name for a route (e.g.,home
,dashboard
,signIn
). - The corresponding value is the actual URL path.
- Paths can include dynamic segments, such as
:id
in/subscription/:id
, whichreact-router-dom
uses to capture URL parameters.
By referencing these paths using config.appConfig.pages.<routeName>
(e.g., config.appConfig.pages.home
) in your App.tsx
and other components, you ensure consistency and simplify updates across your application.
Core Routing Setup (App.tsx
):
The main routing configuration is typically found in your App.tsx
file. Here, you define Routes
and Route
components to map URLs to your application’s views, using the paths defined in app.config.json
. Fireact.dev provides several layout components and a ProtectedSubscriptionRoute
component to streamline this process.
Example (test-app/src/App.tsx
snippet):
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import {
AuthenticatedLayout,
PublicLayout,
SubscriptionLayout,
ProtectedSubscriptionRoute,
// ... other components and providers
} from '@fireact.dev/app';
import appConfig from './config/app.config.json';
function App() {
return (
<Router>
<ConfigProvider firebaseConfig={firebaseConfig.firebase} appConfig={appConfig} stripeConfig={stripeConfig.stripe}>
<AuthProvider>
<LoadingProvider>
<Routes>
{/* Authenticated Routes */}
<Route element={
<AuthenticatedLayout
desktopMenuItems={<MainDesktopMenu />}
mobileMenuItems={<MainMobileMenu />}
logo={<Logo className="w-10 h-10" />}
/>
}>
<Route path={appConfig.pages.home} element={<Navigate to={appConfig.pages.dashboard} />} />
<Route path={appConfig.pages.dashboard} element={<Home />} />
{/* ... other authenticated routes */}
</Route>
{/* Subscription Protected Routes */}
<Route path={appConfig.pages.subscription} element={
<SubscriptionProvider>
<SubscriptionLayout
desktopMenu={<SubscriptionDesktopMenu />}
mobileMenu={<SubscriptionMobileMenu />}
logo={<Logo className="w-10 h-10" />}
/>
</SubscriptionProvider>
}>
<Route index element={
<ProtectedSubscriptionRoute requiredPermissions={['access']}>
<SubscriptionDashboard />
</ProtectedSubscriptionRoute>
} />
<Route path={appConfig.pages.users} element={
<ProtectedSubscriptionRoute requiredPermissions={['admin']}>
<UserList />
</ProtectedSubscriptionRoute>
} />
{/* ... other subscription protected routes */}
</Route>
{/* Public Routes */}
<Route element={<PublicLayout logo={<Logo className="w-20 h-20" />} />}>
<Route path={appConfig.pages.signIn} element={<SignIn />} />
<Route path={appConfig.pages.signUp} element={<SignUp />} />
{/* ... other public routes */}
</Route>
</Routes>
</LoadingProvider>
</AuthProvider>
</ConfigProvider>
</Router>
);
}
Layout Components:
Fireact.dev provides three main layout components to structure your application’s UI based on the user’s authentication and subscription status:
PublicLayout
:- Used for routes accessible to unauthenticated users (e.g., sign-in, sign-up, password reset).
- It typically includes only basic UI elements like a logo and language switcher.
- Source:
source/packages/app/src/layouts/PublicLayout.tsx
AuthenticatedLayout
:- Used for routes accessible to authenticated users who may or may not have an active subscription (e.g., dashboard, profile settings).
- Includes navigation menus (desktop and mobile), user avatar, and sign-out options.
- Source:
source/packages/app/src/layouts/AuthenticatedLayout.tsx
SubscriptionLayout
:- Used for routes that require an active subscription to access (e.g., subscription dashboard, billing, user management).
- Wraps its children with
SubscriptionProvider
to ensure subscription data is available. - Includes subscription-specific navigation menus.
- Source:
source/packages/app/src/layouts/SubscriptionLayout.tsx
These layouts use react-router-dom
’s Outlet
component to render nested routes within their structure.
Permission Control (ProtectedSubscriptionRoute
):
The ProtectedSubscriptionRoute
component is crucial for enforcing access control based on subscription permissions. It wraps components that should only be accessible to users with specific roles or an active subscription.
Source: source/packages/app/src/components/ProtectedSubscriptionRoute.tsx
How it works:
- Authentication Check: First, it checks if the user is authenticated (
currentUser
). If not, it redirects to the sign-in page. - Loading State: Displays a loading spinner while subscription data is being fetched.
- Required Permissions:
- It takes a
requiredPermissions
prop (an array of strings) to specify which permissions are needed to access the route. - It also supports a
requireAll
boolean prop (defaultfalse
), which determines if all specified permissions are required (true
) or if any of them are sufficient (false
).
- It takes a
- “Owner” Permission: There’s special handling for the
'owner'
permission. If'owner'
is required, it checks if thecurrentUser.uid
matches thesubscription.owner_id
. - Invalid Permissions: It validates
requiredPermissions
against theconfig.appConfig.permissions
to ensure only defined permissions are used. Invalid permissions will result in a redirection to the home page. - Permission Check (
hasPermission
): It uses thehasPermission
function (fromuseSubscription
hook) to check if the authenticated user has the necessary permissions based on their subscription. - Redirection: If the user does not meet the required authentication or permission criteria, they are redirected to the
config.appConfig.pages.home
page.
Example Usage in App.tsx
:
<Route index element={
<ProtectedSubscriptionRoute requiredPermissions={['access']}>
<SubscriptionDashboard />
</ProtectedSubscriptionRoute>
} />
<Route path={appConfig.pages.users} element={
<ProtectedSubscriptionRoute requiredPermissions={['admin']}>
<UserList />
</ProtectedSubscriptionRoute>
} />
<Route path={appConfig.pages.changePlan} element={
<ProtectedSubscriptionRoute requiredPermissions={['owner']}>
<ChangePlan PlansComponent={Plans} BillingFormComponent={BillingForm} />
</ProtectedSubscriptionRoute>
} />
In these examples:
SubscriptionDashboard
requires the'access'
permission (meaning any user with an active subscription).UserList
requires the'admin'
permission.ChangePlan
requires the'owner'
permission, ensuring only the subscription owner can access it.
By combining react-router-dom
with Fireact.dev’s layout components and ProtectedSubscriptionRoute
, you can build a robust and secure routing system with fine-grained permission control for your application.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.