Skip to content

[FE-30] Global Error Boundary, 404 Page, Loading Skeletons & Toast System Standardization #1022

Description

@mftee

Overview

The platform has inconsistent error handling across pages, no global error boundary, a missing 404 page, varying loading states, and multiple toast implementations. This issue standardizes error handling and loading UX across the entire application.

Technical Details

1. Global Error Boundary (frontend/app/error.tsx)

Create or update the Next.js root error boundary:

// app/error.tsx — auto-wired by Next.js App Router
'use client';
export default function ErrorBoundary({ error, reset }: { error: Error, reset: () => void }) {
  // Log to console in dev, or to Sentry/observability tool in prod
  return (
    <div className="error-boundary-container">
      <h2>Something went wrong</h2>
      <p>{error.message || 'An unexpected error occurred'}</p>
      <button onClick={reset}>Try again</button>
      <a href="/dashboard">Go to dashboard</a>
    </div>
  );
}

Also create frontend/app/global-error.tsx for root layout errors (same pattern).
Create a frontend/app/(dashboard)/error.tsx specifically for the dashboard section that shows a friendlier "Dashboard failed to load" error with a retry button.

2. Custom 404 Page (frontend/app/not-found.tsx)

Create or update app/not-found.tsx:

  • Illustration: a lost truck SVG or simple "404" large text with a truck icon
  • Heading: "Page Not Found"
  • Subtext: "The page you're looking for doesn't exist or has been moved."
  • Two buttons: "Go to Dashboard" → /dashboard and "Go to Home" → /
  • Use Link from next/link

3. Skeleton Loading Components

Create a set of reusable skeleton components in frontend/components/skeletons/:

  • ShipmentCardSkeleton — matches the shape of a shipment list card
  • TableRowSkeleton — one row of a data table (configurable number of columns)
  • KpiCardSkeleton — matches the KPI card shape from the dashboard
  • ProfileSkeleton — avatar circle + two lines of text
  • NotificationItemSkeleton — matches a notification row

Each skeleton uses a CSS shimmer animation (animate-pulse from Tailwind or a custom keyframe). Export all from frontend/components/skeletons/index.ts.

Audit all existing pages that show a blank or spinning loading state and replace with the appropriate skeleton component:

  • /shipments: use TableRowSkeleton × 5 while loading
  • /dashboard: use KpiCardSkeleton × 4 while loading
  • /notifications: use NotificationItemSkeleton × 5 while loading
  • /bids: use TableRowSkeleton × 3 while loading

4. Toast System Standardization

The project has sonner installed. Audit all existing toast() calls across the frontend and ensure they follow a consistent API:

// All success toasts:
toast.success('Action completed successfully');
// All error toasts:
toast.error('Something went wrong. Please try again.');
// All info toasts:
toast.info('Processing your request...');
  • Remove any direct uses of alert() or console.error() intended as user feedback
  • Ensure the Toaster component from sonner is rendered once in frontend/app/layout.tsx
  • Set default: position: 'top-right', duration: 4000

5. Empty States

Create a reusable <EmptyState /> component (frontend/components/ui/empty-state.tsx):

<EmptyState icon={<TruckIcon />} title="No shipments yet" description="Post your first shipment to get started." action={{ label: 'Post Shipment', href: '/shipments/new' }} />

Use it on all pages that currently show blank or missing content for empty data sets.

Acceptance Criteria

  • Throwing an error inside any dashboard page shows the error boundary UI with a "Try again" button
  • Navigating to a non-existent URL shows the custom 404 page
  • All 5 skeleton components exist in frontend/components/skeletons/
  • /shipments, /dashboard, and /notifications use skeletons while loading
  • No alert() calls remain in the frontend codebase (verify with grep -r 'alert(' frontend/)
  • The Toaster is mounted once in the root layout
  • All success/error toasts use toast.success() and toast.error() consistently
  • <EmptyState /> is used on at least 3 pages (shipments, bids, notifications)

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions