Shoplit
Getting Started

Routing

Learn how to use Shoplit's routing system.

Routing

Shoplit uses Next.js App Router with a structured routing system that includes route groups, protected routes, and authentication-based routing.

Route Structure

app/
├── (auth)/                   # Authentication routes
   ├── login/
   ├── register/
   ├── change-password/
   ├── reset-password/
   └── verify-email/

├── (protected)/             # Protected routes (require authentication)
   ├── dashboard/
   ├── products/
   ├── orders/
   ├── customers/
   ├── categories/
   ├── settings/
   ├── account/
   ├── activity-logs/
   └── user-management/

├── api/                     # API routes
   └── ...

└── shared/                  # Shared components and utilities
    └── ...

Route Groups

Shoplit uses route groups for logical organization:

  1. Authentication Group (auth)

    • Contains all authentication-related pages
    • Uses AuthLayout with centered content
    • Public access
  2. Protected Group (protected)

    • Contains all authenticated user pages
    • Uses DefaultLayout with sidebar navigation
    • Requires authentication

Protected Routes

Protected routes are implemented using a layout wrapper:

// app/(protected)/layout.tsx
'use client';
 
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/navigation';
 
export default function ProtectedLayout({ children }) {
  const { data: session, status } = useSession();
  const router = useRouter();
 
  useEffect(() => {
    if (status === 'unauthenticated') {
      router.push('/login');
    }
  }, [status, router]);
 
  if (status === 'loading') {
    return <ScreenLoader />;
  }
 
  return session ? <DefaultLayout>{children}</DefaultLayout> : null;
}

Use the useRouter hook for programmatic navigation:

import { useRouter } from 'next/navigation';
 
export function ProductList() {
  const router = useRouter();
 
  const handleProductClick = (productId: string) => {
    router.push(`/products/${productId}`);
  };
}

Use the Link component for declarative navigation:

import Link from 'next/link';
 
export function Navigation() {
  return (
    <nav>
      <Link href="/dashboard">Dashboard</Link>
      <Link href="/products">Products</Link>
      <Link href="/orders">Orders</Link>
    </nav>
  );
}

Route Layouts

Auth Layout

Used for authentication pages with centered content:

// app/(auth)/layout.tsx
export default function AuthLayout({ children }) {
  return (
    <div className="flex min-h-screen items-center justify-center">
      {children}
    </div>
  );
}

Default Layout

Used for protected pages with sidebar navigation:

// app/components/layouts/default.tsx
export function DefaultLayout({ children }) {
  return (
    <div className="flex min-h-screen">
      <Sidebar />
      <main className="flex-1">{children}</main>
    </div>
  );
}

Route Protection

Authentication Check

Routes in the (protected) group are automatically protected:

  1. Session Check

    • Verifies user authentication status
    • Redirects to login if unauthenticated
    • Shows loading state during check
  2. Role-Based Access

    • Verifies user permissions
    • Redirects to dashboard if unauthorized
    • Shows appropriate error messages

Example Protected Route

// app/(protected)/products/page.tsx
export default function ProductsPage() {
  const { data: session } = useSession();
  const hasAccess = session?.user.permissions.includes('products.view');
 
  if (!hasAccess) {
    return <AccessDenied />;
  }
 
  return <ProductList />;
}

Route Loading States

Shoplit provides consistent loading states:

  1. Screen Loader

    • Full-screen loading for route changes
    • Used during authentication checks
  2. Skeleton Loading

    • Content-specific loading states
    • Maintains layout structure during data fetch
// Example loading.tsx
export default function Loading() {
  return (
    <div className="space-y-4">
      <Skeleton className="h-8 w-full" />
      <Skeleton className="h-4 w-3/4" />
      <Skeleton className="h-4 w-1/2" />
    </div>
  );
}

Error Handling

Error Pages

Custom error pages for different scenarios:

  1. Not Found (404)

    // app/not-found.tsx
    export default function NotFound() {
      return (
        <div className="text-center">
          <h1>Page Not Found</h1>
          <p>The page you're looking for doesn't exist.</p>
        </div>
      );
    }
  2. Error Boundary

    // app/error.tsx
    'use client';
     
    export default function Error({
      error,
      reset,
    }: {
      error: Error;
      reset: () => void;
    }) {
      return (
        <div className="text-center">
          <h1>Something went wrong</h1>
          <button onClick={reset}>Try again</button>
        </div>
      );
    }

Best Practices

  1. Route Organization

    • Use route groups for logical separation
    • Keep related routes together
    • Follow consistent naming conventions
  2. Performance

    • Implement loading states
    • Use dynamic imports for large components
    • Optimize page transitions
  3. Security

    • Always verify authentication in protected routes
    • Implement proper role checks
    • Handle sensitive data appropriately
  4. User Experience

    • Provide clear navigation paths
    • Show appropriate loading states
    • Handle errors gracefully