Routing & Sidebar
Router Structure
const router = createBrowserRouter([
{ path: '/login', element: <LoginPage />, errorElement: <ErrorBoundary /> },
{
path: '/',
element: <RequireAuth><App /></RequireAuth>,
errorElement: <ErrorBoundary />,
children: [
{ index: true, element: <Navigate to="/dashboard" /> },
...categoryRoutes,
...productRoutes,
],
},
{ path: '*', element: <NotFound /> },
]);
New apps: split routes per feature in routes/features/*.routes.tsx.
Legacy: monolithic routes/router.tsx — add imports + route objects.
App Shell
// App.tsx
<DashboardLayout>
<Outlet />
<Toaster />
</DashboardLayout>
Sidebar Config
// config/sidebar.ts
export const sidebarGroups: SidebarGroup[] = [
{
title: 'Catalog',
icon: Package,
roles: ['ADMIN', 'EDITOR'],
links: [
{ title: 'Categories', href: '/dashboard/categories' },
{ title: 'Products', href: '/dashboard/products' },
],
},
];
Layout filters by user.role. Optional notificationKey for badge dots.
Nested Tab Layout (orders)
// OrdersManagementLayout.tsx
<nav>{tabs.map(t => <NavLink key={t.path} to={t.path}>{t.label} {t.count}</NavLink>)}</nav>
<Outlet />
Breadcrumbs
<Breadcrumbs items={[
{ label: 'Homepages', href: '/dashboard/homepages' },
{ label: homepage.name, bold: true },
]} />
Route Conventions
| Pattern | Example |
|---|---|
| List | /dashboard/{resource} |
| Create | /dashboard/{resource}/create |
| Edit | /dashboard/{resource}/edit/:id |
| Nested | /dashboard/homepages/:id/sections/:sectionId/elements |
Role on Every Protected Route
<RequireRole roles={['ADMIN', 'EDITOR']}><Page /></RequireRole>
Must match sidebar roles array.