This commit introduces a comprehensive documentation strategy for the project, focusing on: - Centralizing routing configuration - Adding detailed documentation for frontend architecture - Creating standards for component documentation - Implementing a feature building process template - Removing legacy documentation files Key changes include: - Added routing strategy and implementation documents - Created project-wide documentation standards - Introduced new documentation structure in qwrk-docs - Removed redundant README and documentation files - Enhanced routing and layout documentation
6.7 KiB
Routing Strategy
This document outlines the new routing strategy for the frontend package. The goal is to consolidate the routing into a centralized configuration while maintaining all existing functionality.
Core Principles
- Single Source of Truth: All routes will be defined in a centralized location.
- Type Safety: Comprehensive TypeScript typing for route definitions.
- Error Handling: Consistent error boundaries for all routes.
- Loading States: Standardized loading states using the LoadingOverlay component.
- Code Splitting: Lazy loading of components for improved performance.
- 404 Handling: Graceful handling of not found routes.
Architecture Overview
graph TD
A[App.tsx] --> B[routes/index.tsx]
B --> C[Route Configuration]
C --> D[Public Routes]
C --> E[Protected Routes]
C --> F[Catch-all Route]
D --> G[Lazy-loaded Components]
E --> H[Lazy-loaded Components]
G --> I[Error Boundaries]
H --> I
I --> J[Loading States]
style A fill:#d4f1f9,stroke:#05a4c9
style B fill:#d4f1f9,stroke:#05a4c9
style C fill:#d4f1f9,stroke:#05a4c9
style F fill:#ffe6cc,stroke:#d79b00
style I fill:#f8cecc,stroke:#b85450
style J fill:#d5e8d4,stroke:#82b366
Centralized Route Configuration
All routes will be defined in a single file: src/routes/index.tsx. This file will export a router
instance created using createBrowserRouter from React Router v6.
// src/routes/index.tsx
import { createBrowserRouter, RouteObject } from 'react-router-dom';
import { ErrorBoundary } from '@/components/error/ErrorBoundary';
import { NotFound } from '@/components/error/NotFound';
// Type definitions for route objects
export interface AppRouteObject extends RouteObject {
// Additional properties for our routes
auth?: boolean;
title?: string;
}
// Route definitions
const routes: AppRouteObject[] = [
// Public routes
{
path: '/',
element: <RootLayout />,
errorElement: <ErrorBoundary />,
children: [
// Home page
{
index: true,
lazy: () => import('@/pages/Index'),
},
// Login page
{
path: 'login',
lazy: () => import('@/pages/AuthPage'),
},
// Buy prepaid service
{
path: 'buy-prepaid-service',
lazy: () => import('@/pages/BuyPrepaidService'),
},
// Organization routes
{
path: ':orgSlug',
lazy: () => import('@/layouts/DashboardLayout'),
children: [
// Organization routes...
],
},
// 404 page
{
path: '*',
element: <NotFound />,
},
],
},
];
// Create and export the router
export const router = createBrowserRouter(routes);
Error Boundaries
A reusable error boundary component will be created to handle errors consistently across the application.
// src/components/error/ErrorBoundary.tsx
import { useRouteError, isRouteErrorResponse, useNavigate } from 'react-router-dom';
import { Button } from '@/components/ui/button';
export function ErrorBoundary() {
const error = useRouteError();
const navigate = useNavigate();
// Handle different types of errors
let errorMessage = 'An unexpected error occurred';
let statusCode = 500;
if (isRouteErrorResponse(error)) {
statusCode = error.status;
errorMessage = error.statusText || errorMessage;
} else if (error instanceof Error) {
errorMessage = error.message;
}
return (
<div className='flex flex-col items-center justify-center min-h-screen p-4'>
<h1 className='text-4xl font-bold mb-4'>Something went wrong</h1>
<p className='text-xl mb-6'>{errorMessage}</p>
<div className='flex gap-4'>
<Button onClick={() => navigate(-1)}>Go Back</Button>
<Button onClick={() => navigate('/')}>Go Home</Button>
</div>
</div>
);
}
Loading States
The existing LoadingOverlay component will be used for loading states when lazy loading components.
// Example of lazy loading with LoadingOverlay
const ProjectsPage = React.lazy(() => import('@/pages/org-slug/ProjectsScreen'));
// In route definition
{
path: 'projects',
element: (
<React.Suspense fallback={<LoadingOverlay />}>
<ProjectsPage />
</React.Suspense>
),
}
Lazy Loading
Components will be lazy loaded using React.lazy and dynamic imports. This will be implemented using
the lazy property of route objects in React Router v6.4+.
// Example of lazy loading with the lazy property
{
path: 'settings',
lazy: () => import('@/pages/org-slug/Settings'),
}
The lazy function should return an object with either an element property or a Component
property. For example:
// src/pages/org-slug/Settings.tsx
export function Component() {
return <SettingsPage />;
}
Or:
// src/pages/org-slug/Settings.tsx
export default function Settings() {
return <SettingsPage />;
}
404 Handling
A dedicated NotFound component will be created to handle 404 errors gracefully.
// src/components/error/NotFound.tsx
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/button';
export function NotFound() {
return (
<div className='flex flex-col items-center justify-center min-h-screen p-4'>
<h1 className='text-4xl font-bold mb-4'>404 - Page Not Found</h1>
<p className='text-xl mb-6'>The page you are looking for does not exist.</p>
<Button asChild>
<Link to='/'>Go Home</Link>
</Button>
</div>
);
}
Type Safety
TypeScript types will be defined for route objects to ensure type safety and provide better developer experience.
// src/types/route.ts
import { RouteObject } from 'react-router-dom';
export interface AppRouteObject extends RouteObject {
auth?: boolean; // Whether the route requires authentication
title?: string; // Page title
children?: AppRouteObject[]; // Nested routes
}
Benefits of the New Strategy
- Improved Maintainability: All routes are defined in a single location, making it easier to understand and maintain the routing structure.
- Better Error Handling: Consistent error boundaries for all routes.
- Improved Performance: Lazy loading of components reduces the initial bundle size and improves load times.
- Better User Experience: Standardized loading states and 404 handling.
- Type Safety: Comprehensive TypeScript typing for route definitions.
- Easier Navigation: Centralized route configuration makes it easier to navigate between routes programmatically.
- Better Developer Experience: Clear structure and documentation make it easier for developers to work with the routing system.