laconic-deploy/qwrk-docs/project-docs/frontend/ROUTING_STRATEGY.md
icld e1c2a8ce2c refactor: consolidate project documentation and routing strategy
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
2025-03-02 06:14:24 -08:00

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

  1. Single Source of Truth: All routes will be defined in a centralized location.
  2. Type Safety: Comprehensive TypeScript typing for route definitions.
  3. Error Handling: Consistent error boundaries for all routes.
  4. Loading States: Standardized loading states using the LoadingOverlay component.
  5. Code Splitting: Lazy loading of components for improved performance.
  6. 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

  1. Improved Maintainability: All routes are defined in a single location, making it easier to understand and maintain the routing structure.
  2. Better Error Handling: Consistent error boundaries for all routes.
  3. Improved Performance: Lazy loading of components reduces the initial bundle size and improves load times.
  4. Better User Experience: Standardized loading states and 404 handling.
  5. Type Safety: Comprehensive TypeScript typing for route definitions.
  6. Easier Navigation: Centralized route configuration makes it easier to navigate between routes programmatically.
  7. Better Developer Experience: Clear structure and documentation make it easier for developers to work with the routing system.